xref: /xnu-8796.121.2/iokit/Kernel/IOServicePM.cpp (revision c54f35ca767986246321eb901baf8f5ff7923f6a)
1*c54f35caSApple OSS Distributions /*
2*c54f35caSApple OSS Distributions  * Copyright (c) 1998-2020 Apple Inc. All rights reserved.
3*c54f35caSApple OSS Distributions  *
4*c54f35caSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*c54f35caSApple OSS Distributions  *
6*c54f35caSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*c54f35caSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*c54f35caSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*c54f35caSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*c54f35caSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*c54f35caSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*c54f35caSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*c54f35caSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*c54f35caSApple OSS Distributions  *
15*c54f35caSApple OSS Distributions  * Please obtain a copy of the License at
16*c54f35caSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*c54f35caSApple OSS Distributions  *
18*c54f35caSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*c54f35caSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*c54f35caSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*c54f35caSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*c54f35caSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*c54f35caSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*c54f35caSApple OSS Distributions  * limitations under the License.
25*c54f35caSApple OSS Distributions  *
26*c54f35caSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*c54f35caSApple OSS Distributions  */
28*c54f35caSApple OSS Distributions 
29*c54f35caSApple OSS Distributions #include <IOKit/assert.h>
30*c54f35caSApple OSS Distributions #include <IOKit/IOKitDebug.h>
31*c54f35caSApple OSS Distributions #include <IOKit/IOLib.h>
32*c54f35caSApple OSS Distributions #include <IOKit/IOMessage.h>
33*c54f35caSApple OSS Distributions #include <IOKit/IOPlatformExpert.h>
34*c54f35caSApple OSS Distributions #include <IOKit/IOService.h>
35*c54f35caSApple OSS Distributions #include <IOKit/IOUserServer.h>
36*c54f35caSApple OSS Distributions #include <IOKit/IOEventSource.h>
37*c54f35caSApple OSS Distributions #include <IOKit/IOWorkLoop.h>
38*c54f35caSApple OSS Distributions #include <IOKit/IOCommand.h>
39*c54f35caSApple OSS Distributions #include <IOKit/IOTimeStamp.h>
40*c54f35caSApple OSS Distributions #include <IOKit/IOReportMacros.h>
41*c54f35caSApple OSS Distributions #include <IOKit/IODeviceTreeSupport.h>
42*c54f35caSApple OSS Distributions 
43*c54f35caSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMlog.h>
44*c54f35caSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMinformee.h>
45*c54f35caSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMinformeeList.h>
46*c54f35caSApple OSS Distributions #include <IOKit/pwr_mgt/IOPowerConnection.h>
47*c54f35caSApple OSS Distributions #include <IOKit/pwr_mgt/RootDomain.h>
48*c54f35caSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMPrivate.h>
49*c54f35caSApple OSS Distributions 
50*c54f35caSApple OSS Distributions #include <sys/proc.h>
51*c54f35caSApple OSS Distributions #include <sys/proc_internal.h>
52*c54f35caSApple OSS Distributions #include <sys/sysctl.h>
53*c54f35caSApple OSS Distributions #include <libkern/OSDebug.h>
54*c54f35caSApple OSS Distributions #include <kern/thread.h>
55*c54f35caSApple OSS Distributions 
56*c54f35caSApple OSS Distributions // Required for notification instrumentation
57*c54f35caSApple OSS Distributions #include "IOServicePrivate.h"
58*c54f35caSApple OSS Distributions #include "IOServicePMPrivate.h"
59*c54f35caSApple OSS Distributions #include "IOKitKernelInternal.h"
60*c54f35caSApple OSS Distributions 
61*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
62*c54f35caSApple OSS Distributions static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
63*c54f35caSApple OSS Distributions #endif
64*c54f35caSApple OSS Distributions static void idle_timer_expired(thread_call_param_t, thread_call_param_t);
65*c54f35caSApple OSS Distributions static void tellKernelClientApplier(OSObject * object, void * arg);
66*c54f35caSApple OSS Distributions static void tellAppClientApplier(OSObject * object, void * arg);
67*c54f35caSApple OSS Distributions static const char * getNotificationPhaseString(uint32_t phase);
68*c54f35caSApple OSS Distributions 
69*c54f35caSApple OSS Distributions static uint64_t
computeTimeDeltaNS(const AbsoluteTime * start)70*c54f35caSApple OSS Distributions computeTimeDeltaNS( const AbsoluteTime * start )
71*c54f35caSApple OSS Distributions {
72*c54f35caSApple OSS Distributions 	AbsoluteTime    now;
73*c54f35caSApple OSS Distributions 	uint64_t        nsec;
74*c54f35caSApple OSS Distributions 
75*c54f35caSApple OSS Distributions 	clock_get_uptime(&now);
76*c54f35caSApple OSS Distributions 	SUB_ABSOLUTETIME(&now, start);
77*c54f35caSApple OSS Distributions 	absolutetime_to_nanoseconds(now, &nsec);
78*c54f35caSApple OSS Distributions 	return nsec;
79*c54f35caSApple OSS Distributions }
80*c54f35caSApple OSS Distributions 
81*c54f35caSApple OSS Distributions #if PM_VARS_SUPPORT
82*c54f35caSApple OSS Distributions OSDefineMetaClassAndStructors(IOPMprot, OSObject)
83*c54f35caSApple OSS Distributions #endif
84*c54f35caSApple OSS Distributions 
85*c54f35caSApple OSS Distributions //******************************************************************************
86*c54f35caSApple OSS Distributions // Globals
87*c54f35caSApple OSS Distributions //******************************************************************************
88*c54f35caSApple OSS Distributions 
89*c54f35caSApple OSS Distributions static bool                  gIOPMInitialized       = false;
90*c54f35caSApple OSS Distributions static uint32_t              gIOPMBusyRequestCount  = 0;
91*c54f35caSApple OSS Distributions static uint32_t              gIOPMWorkInvokeCount   = 0;
92*c54f35caSApple OSS Distributions static uint32_t              gIOPMTickleGeneration  = 0;
93*c54f35caSApple OSS Distributions static IOWorkLoop *          gIOPMWorkLoop          = NULL;
94*c54f35caSApple OSS Distributions static IOPMRequestQueue *    gIOPMRequestQueue      = NULL;
95*c54f35caSApple OSS Distributions static IOPMRequestQueue *    gIOPMReplyQueue        = NULL;
96*c54f35caSApple OSS Distributions static IOPMWorkQueue *       gIOPMWorkQueue         = NULL;
97*c54f35caSApple OSS Distributions static IOPMCompletionQueue * gIOPMCompletionQueue   = NULL;
98*c54f35caSApple OSS Distributions static IOPMRequest *         gIOPMRequest           = NULL;
99*c54f35caSApple OSS Distributions static IOService *           gIOPMRootNode          = NULL;
100*c54f35caSApple OSS Distributions static IOPlatformExpert *    gPlatform              = NULL;
101*c54f35caSApple OSS Distributions static IOLock *              gIOPMInitLock          = NULL;
102*c54f35caSApple OSS Distributions 
103*c54f35caSApple OSS Distributions // log setPowerStates and powerStateChange longer than (ns):
104*c54f35caSApple OSS Distributions static uint64_t              gIOPMSetPowerStateLogNS =
105*c54f35caSApple OSS Distributions #if defined(__i386__) || defined(__x86_64__)
106*c54f35caSApple OSS Distributions     (300ULL * 1000ULL * 1000ULL)
107*c54f35caSApple OSS Distributions #else
108*c54f35caSApple OSS Distributions     (50ULL * 1000ULL * 1000ULL)
109*c54f35caSApple OSS Distributions #endif
110*c54f35caSApple OSS Distributions ;
111*c54f35caSApple OSS Distributions 
112*c54f35caSApple OSS Distributions const OSSymbol *             gIOPMPowerClientDevice     = NULL;
113*c54f35caSApple OSS Distributions const OSSymbol *             gIOPMPowerClientDriver     = NULL;
114*c54f35caSApple OSS Distributions const OSSymbol *             gIOPMPowerClientChildProxy = NULL;
115*c54f35caSApple OSS Distributions const OSSymbol *             gIOPMPowerClientChildren   = NULL;
116*c54f35caSApple OSS Distributions const OSSymbol *             gIOPMPowerClientRootDomain = NULL;
117*c54f35caSApple OSS Distributions 
118*c54f35caSApple OSS Distributions static const OSSymbol *      gIOPMPowerClientAdvisoryTickle = NULL;
119*c54f35caSApple OSS Distributions static bool                  gIOPMAdvisoryTickleEnabled = true;
120*c54f35caSApple OSS Distributions static thread_t              gIOPMWatchDogThread        = NULL;
121*c54f35caSApple OSS Distributions TUNABLE_WRITEABLE(uint32_t, gSleepAckTimeout, "pmtimeout", 0);
122*c54f35caSApple OSS Distributions 
123*c54f35caSApple OSS Distributions /*
124*c54f35caSApple OSS Distributions  *  While waiting for a driver callout to complete, we log any instances
125*c54f35caSApple OSS Distributions  *  that have taken longer than the below period (in milliseconds) to return.
126*c54f35caSApple OSS Distributions  */
127*c54f35caSApple OSS Distributions TUNABLE_WRITEABLE(uint32_t, gDriverCalloutTimer, "pmcallouttimer", 2000);
128*c54f35caSApple OSS Distributions 
129*c54f35caSApple OSS Distributions static uint32_t
getPMRequestType(void)130*c54f35caSApple OSS Distributions getPMRequestType( void )
131*c54f35caSApple OSS Distributions {
132*c54f35caSApple OSS Distributions 	uint32_t type = kIOPMRequestTypeInvalid;
133*c54f35caSApple OSS Distributions 	if (gIOPMRequest) {
134*c54f35caSApple OSS Distributions 		type = gIOPMRequest->getType();
135*c54f35caSApple OSS Distributions 	}
136*c54f35caSApple OSS Distributions 	return type;
137*c54f35caSApple OSS Distributions }
138*c54f35caSApple OSS Distributions 
139*c54f35caSApple OSS Distributions SYSCTL_UINT(_kern, OID_AUTO, pmtimeout, CTLFLAG_RW | CTLFLAG_LOCKED, &gSleepAckTimeout, 0, "Power Management Timeout");
140*c54f35caSApple OSS Distributions SYSCTL_UINT(_kern, OID_AUTO, pmcallouttimer, CTLFLAG_RW | CTLFLAG_LOCKED, &gDriverCalloutTimer, 0, "Power Management Driver Callout Log Timer");
141*c54f35caSApple OSS Distributions 
142*c54f35caSApple OSS Distributions //******************************************************************************
143*c54f35caSApple OSS Distributions // Macros
144*c54f35caSApple OSS Distributions //******************************************************************************
145*c54f35caSApple OSS Distributions 
146*c54f35caSApple OSS Distributions #define PM_ERROR(x...)              do { kprintf(x);IOLog(x); \
147*c54f35caSApple OSS Distributions 	                            } while (false)
148*c54f35caSApple OSS Distributions #define PM_LOG(x...)                do { kprintf(x); } while (false)
149*c54f35caSApple OSS Distributions 
150*c54f35caSApple OSS Distributions #define PM_LOG1(x...)               do {  \
151*c54f35caSApple OSS Distributions 	                            if (kIOLogDebugPower & gIOKitDebug) \
152*c54f35caSApple OSS Distributions 	                                kprintf(x); } while (false)
153*c54f35caSApple OSS Distributions 
154*c54f35caSApple OSS Distributions #define PM_LOG2(x...)               do {  \
155*c54f35caSApple OSS Distributions 	                            if (kIOLogDebugPower & gIOKitDebug) \
156*c54f35caSApple OSS Distributions 	                                kprintf(x); } while (false)
157*c54f35caSApple OSS Distributions 
158*c54f35caSApple OSS Distributions #if 0
159*c54f35caSApple OSS Distributions #define PM_LOG3(x...)               do { kprintf(x); } while (false)
160*c54f35caSApple OSS Distributions #else
161*c54f35caSApple OSS Distributions #define PM_LOG3(x...)
162*c54f35caSApple OSS Distributions #endif
163*c54f35caSApple OSS Distributions 
164*c54f35caSApple OSS Distributions #define RD_LOG(x...)                do { \
165*c54f35caSApple OSS Distributions 	                            if ((kIOLogPMRootDomain & gIOKitDebug) && \
166*c54f35caSApple OSS Distributions 	                                (getPMRootDomain() == this)) { \
167*c54f35caSApple OSS Distributions 	                                kprintf("PMRD: " x); \
168*c54f35caSApple OSS Distributions 	                            }} while (false)
169*c54f35caSApple OSS Distributions #define PM_ASSERT_IN_GATE(x)          \
170*c54f35caSApple OSS Distributions do {                                  \
171*c54f35caSApple OSS Distributions     assert(gIOPMWorkLoop->inGate());  \
172*c54f35caSApple OSS Distributions } while(false)
173*c54f35caSApple OSS Distributions 
174*c54f35caSApple OSS Distributions #define PM_LOCK()                   IOLockLock(fPMLock)
175*c54f35caSApple OSS Distributions #define PM_UNLOCK()                 IOLockUnlock(fPMLock)
176*c54f35caSApple OSS Distributions #define PM_LOCK_SLEEP(event, dl)    IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
177*c54f35caSApple OSS Distributions #define PM_LOCK_WAKEUP(event)       IOLockWakeup(fPMLock, event, false)
178*c54f35caSApple OSS Distributions 
179*c54f35caSApple OSS Distributions #define us_per_s                    1000000
180*c54f35caSApple OSS Distributions #define ns_per_us                   1000
181*c54f35caSApple OSS Distributions #define k30Seconds                  (30*us_per_s)
182*c54f35caSApple OSS Distributions #define k5Seconds                   ( 5*us_per_s)
183*c54f35caSApple OSS Distributions #define k7Seconds                   ( 7*us_per_s)
184*c54f35caSApple OSS Distributions #if !defined(XNU_TARGET_OS_OSX)
185*c54f35caSApple OSS Distributions #define kCanSleepMaxTimeReq         k5Seconds
186*c54f35caSApple OSS Distributions #define kWillSleepMaxTimeReq        k7Seconds
187*c54f35caSApple OSS Distributions #else /* defined(XNU_TARGET_OS_OSX) */
188*c54f35caSApple OSS Distributions #define kCanSleepMaxTimeReq         k30Seconds
189*c54f35caSApple OSS Distributions #define kWillSleepMaxTimeReq        k30Seconds
190*c54f35caSApple OSS Distributions #endif /* defined(XNU_TARGET_OS_OSX) */
191*c54f35caSApple OSS Distributions #define kMaxTimeRequested           k30Seconds
192*c54f35caSApple OSS Distributions #define kMinAckTimeoutTicks         (10*1000000)
193*c54f35caSApple OSS Distributions #define kIOPMTardyAckSPSKey         "IOPMTardyAckSetPowerState"
194*c54f35caSApple OSS Distributions #define kIOPMTardyAckPSCKey         "IOPMTardyAckPowerStateChange"
195*c54f35caSApple OSS Distributions #define kPwrMgtKey                  "IOPowerManagement"
196*c54f35caSApple OSS Distributions 
197*c54f35caSApple OSS Distributions #define OUR_PMLog(t, a, b) do {                 \
198*c54f35caSApple OSS Distributions     if (pwrMgt) {                               \
199*c54f35caSApple OSS Distributions 	if (gIOKitDebug & kIOLogPower)          \
200*c54f35caSApple OSS Distributions 	    pwrMgt->pmPrint(t, a, b);           \
201*c54f35caSApple OSS Distributions 	if (gIOKitTrace & kIOTracePowerMgmt)    \
202*c54f35caSApple OSS Distributions 	    pwrMgt->pmTrace(t, DBG_FUNC_NONE, a, b);        \
203*c54f35caSApple OSS Distributions     }                                           \
204*c54f35caSApple OSS Distributions     } while(0)
205*c54f35caSApple OSS Distributions 
206*c54f35caSApple OSS Distributions #define OUR_PMLogFuncStart(t, a, b) do {        \
207*c54f35caSApple OSS Distributions     if (pwrMgt) {                               \
208*c54f35caSApple OSS Distributions 	if (gIOKitDebug & kIOLogPower)          \
209*c54f35caSApple OSS Distributions 	    pwrMgt->pmPrint(t, a, b);           \
210*c54f35caSApple OSS Distributions 	if (gIOKitTrace & kIOTracePowerMgmt)    \
211*c54f35caSApple OSS Distributions 	    pwrMgt->pmTrace(t, DBG_FUNC_START, a, b);       \
212*c54f35caSApple OSS Distributions     }                                           \
213*c54f35caSApple OSS Distributions     } while(0)
214*c54f35caSApple OSS Distributions 
215*c54f35caSApple OSS Distributions #define OUR_PMLogFuncEnd(t, a, b) do {          \
216*c54f35caSApple OSS Distributions     if (pwrMgt) {                               \
217*c54f35caSApple OSS Distributions 	if (gIOKitDebug & kIOLogPower)          \
218*c54f35caSApple OSS Distributions 	    pwrMgt->pmPrint(-t, a, b);          \
219*c54f35caSApple OSS Distributions 	if (gIOKitTrace & kIOTracePowerMgmt)    \
220*c54f35caSApple OSS Distributions 	    pwrMgt->pmTrace(t, DBG_FUNC_END, a, b);        \
221*c54f35caSApple OSS Distributions     }                                           \
222*c54f35caSApple OSS Distributions     } while(0)
223*c54f35caSApple OSS Distributions 
224*c54f35caSApple OSS Distributions #define NS_TO_MS(nsec)              ((int)((nsec) / 1000000ULL))
225*c54f35caSApple OSS Distributions #define NS_TO_US(nsec)              ((int)((nsec) / 1000ULL))
226*c54f35caSApple OSS Distributions 
227*c54f35caSApple OSS Distributions #define SUPPORT_IDLE_CANCEL         1
228*c54f35caSApple OSS Distributions 
229*c54f35caSApple OSS Distributions #define kIOPMPowerStateMax          0xFFFFFFFF
230*c54f35caSApple OSS Distributions #define kInvalidTicklePowerState    kIOPMPowerStateMax
231*c54f35caSApple OSS Distributions 
232*c54f35caSApple OSS Distributions #define kNoTickleCancelWindow       (60ULL * 1000ULL * 1000ULL * 1000ULL)
233*c54f35caSApple OSS Distributions 
234*c54f35caSApple OSS Distributions #define IS_PM_ROOT                  (this == gIOPMRootNode)
235*c54f35caSApple OSS Distributions #define IS_ROOT_DOMAIN              (getPMRootDomain() == this)
236*c54f35caSApple OSS Distributions #define IS_POWER_DROP               (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState))
237*c54f35caSApple OSS Distributions #define IS_POWER_RISE               (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState))
238*c54f35caSApple OSS Distributions 
239*c54f35caSApple OSS Distributions // log app responses longer than (ns):
240*c54f35caSApple OSS Distributions #define LOG_APP_RESPONSE_TIMES      (100ULL * 1000ULL * 1000ULL)
241*c54f35caSApple OSS Distributions // use message tracer to log messages longer than (ns):
242*c54f35caSApple OSS Distributions #define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
243*c54f35caSApple OSS Distributions 
244*c54f35caSApple OSS Distributions // log kext responses longer than (ns):
245*c54f35caSApple OSS Distributions #define LOG_KEXT_RESPONSE_TIMES     (100ULL * 1000ULL * 1000ULL)
246*c54f35caSApple OSS Distributions 
247*c54f35caSApple OSS Distributions enum {
248*c54f35caSApple OSS Distributions 	kReserveDomainPower = 1
249*c54f35caSApple OSS Distributions };
250*c54f35caSApple OSS Distributions 
251*c54f35caSApple OSS Distributions #define MS_PUSH(n)  \
252*c54f35caSApple OSS Distributions     do { assert(kIOPM_BadMachineState == fSavedMachineState); \
253*c54f35caSApple OSS Distributions 	 assert(kIOPM_BadMachineState != n); \
254*c54f35caSApple OSS Distributions 	 fSavedMachineState = n; } while (false)
255*c54f35caSApple OSS Distributions 
256*c54f35caSApple OSS Distributions #define MS_POP()    \
257*c54f35caSApple OSS Distributions     do { assert(kIOPM_BadMachineState != fSavedMachineState); \
258*c54f35caSApple OSS Distributions 	 fMachineState = fSavedMachineState; \
259*c54f35caSApple OSS Distributions 	 fSavedMachineState = kIOPM_BadMachineState; } while (false)
260*c54f35caSApple OSS Distributions 
261*c54f35caSApple OSS Distributions #define PM_ACTION_TICKLE(a) \
262*c54f35caSApple OSS Distributions     do { if (fPMActions.a) { \
263*c54f35caSApple OSS Distributions 	 (fPMActions.a)(fPMActions.target, this, &fPMActions); } \
264*c54f35caSApple OSS Distributions 	 } while (false)
265*c54f35caSApple OSS Distributions 
266*c54f35caSApple OSS Distributions #define PM_ACTION_CHANGE(a, x, y) \
267*c54f35caSApple OSS Distributions     do { if (fPMActions.a) { \
268*c54f35caSApple OSS Distributions 	 (fPMActions.a)(fPMActions.target, this, &fPMActions, gIOPMRequest, x, y); } \
269*c54f35caSApple OSS Distributions 	 } while (false)
270*c54f35caSApple OSS Distributions 
271*c54f35caSApple OSS Distributions #define PM_ACTION_CLIENT(a, x, y, z) \
272*c54f35caSApple OSS Distributions     do { if (fPMActions.a) { \
273*c54f35caSApple OSS Distributions 	 (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y, z); } \
274*c54f35caSApple OSS Distributions 	 } while (false)
275*c54f35caSApple OSS Distributions 
276*c54f35caSApple OSS Distributions static OSNumber * copyClientIDForNotification(
277*c54f35caSApple OSS Distributions 	OSObject *object,
278*c54f35caSApple OSS Distributions 	IOPMInterestContext *context);
279*c54f35caSApple OSS Distributions 
280*c54f35caSApple OSS Distributions static void logClientIDForNotification(
281*c54f35caSApple OSS Distributions 	OSObject *object,
282*c54f35caSApple OSS Distributions 	IOPMInterestContext *context,
283*c54f35caSApple OSS Distributions 	const char *logString);
284*c54f35caSApple OSS Distributions 
285*c54f35caSApple OSS Distributions //*********************************************************************************
286*c54f35caSApple OSS Distributions // PM machine states
287*c54f35caSApple OSS Distributions //
288*c54f35caSApple OSS Distributions // Check kgmacros after modifying machine states.
289*c54f35caSApple OSS Distributions //*********************************************************************************
290*c54f35caSApple OSS Distributions 
291*c54f35caSApple OSS Distributions enum {
292*c54f35caSApple OSS Distributions 	kIOPM_Finished                                      = 0,
293*c54f35caSApple OSS Distributions 
294*c54f35caSApple OSS Distributions 	kIOPM_OurChangeTellClientsPowerDown                 = 1,
295*c54f35caSApple OSS Distributions 	kIOPM_OurChangeTellUserPMPolicyPowerDown            = 2,
296*c54f35caSApple OSS Distributions 	kIOPM_OurChangeTellPriorityClientsPowerDown         = 3,
297*c54f35caSApple OSS Distributions 	kIOPM_OurChangeNotifyInterestedDriversWillChange    = 4,
298*c54f35caSApple OSS Distributions 	kIOPM_OurChangeSetPowerState                        = 5,
299*c54f35caSApple OSS Distributions 	kIOPM_OurChangeWaitForPowerSettle                   = 6,
300*c54f35caSApple OSS Distributions 	kIOPM_OurChangeNotifyInterestedDriversDidChange     = 7,
301*c54f35caSApple OSS Distributions 	kIOPM_OurChangeTellCapabilityDidChange              = 8,
302*c54f35caSApple OSS Distributions 	kIOPM_OurChangeFinish                               = 9,
303*c54f35caSApple OSS Distributions 
304*c54f35caSApple OSS Distributions 	kIOPM_ParentChangeTellPriorityClientsPowerDown      = 10,
305*c54f35caSApple OSS Distributions 	kIOPM_ParentChangeNotifyInterestedDriversWillChange = 11,
306*c54f35caSApple OSS Distributions 	kIOPM_ParentChangeSetPowerState                     = 12,
307*c54f35caSApple OSS Distributions 	kIOPM_ParentChangeWaitForPowerSettle                = 13,
308*c54f35caSApple OSS Distributions 	kIOPM_ParentChangeNotifyInterestedDriversDidChange  = 14,
309*c54f35caSApple OSS Distributions 	kIOPM_ParentChangeTellCapabilityDidChange           = 15,
310*c54f35caSApple OSS Distributions 	kIOPM_ParentChangeAcknowledgePowerChange            = 16,
311*c54f35caSApple OSS Distributions 
312*c54f35caSApple OSS Distributions 	kIOPM_NotifyChildrenStart                           = 17,
313*c54f35caSApple OSS Distributions 	kIOPM_NotifyChildrenOrdered                         = 18,
314*c54f35caSApple OSS Distributions 	kIOPM_NotifyChildrenDelayed                         = 19,
315*c54f35caSApple OSS Distributions 	kIOPM_SyncTellClientsPowerDown                      = 20,
316*c54f35caSApple OSS Distributions 	kIOPM_SyncTellPriorityClientsPowerDown              = 21,
317*c54f35caSApple OSS Distributions 	kIOPM_SyncNotifyWillChange                          = 22,
318*c54f35caSApple OSS Distributions 	kIOPM_SyncNotifyDidChange                           = 23,
319*c54f35caSApple OSS Distributions 	kIOPM_SyncTellCapabilityDidChange                   = 24,
320*c54f35caSApple OSS Distributions 	kIOPM_SyncFinish                                    = 25,
321*c54f35caSApple OSS Distributions 	kIOPM_TellCapabilityChangeDone                      = 26,
322*c54f35caSApple OSS Distributions 	kIOPM_DriverThreadCallDone                          = 27,
323*c54f35caSApple OSS Distributions 
324*c54f35caSApple OSS Distributions 	kIOPM_BadMachineState                               = 0xFFFFFFFF
325*c54f35caSApple OSS Distributions };
326*c54f35caSApple OSS Distributions 
327*c54f35caSApple OSS Distributions //*********************************************************************************
328*c54f35caSApple OSS Distributions // [private static] allocPMInitLock
329*c54f35caSApple OSS Distributions //
330*c54f35caSApple OSS Distributions // Allocate gIOPMInitLock prior to gIOPMWorkLoop initialization.
331*c54f35caSApple OSS Distributions //*********************************************************************************
332*c54f35caSApple OSS Distributions 
333*c54f35caSApple OSS Distributions void
allocPMInitLock(void)334*c54f35caSApple OSS Distributions IOService::allocPMInitLock( void )
335*c54f35caSApple OSS Distributions {
336*c54f35caSApple OSS Distributions 	gIOPMInitLock = IOLockAlloc();
337*c54f35caSApple OSS Distributions 	assert(gIOPMInitLock);
338*c54f35caSApple OSS Distributions }
339*c54f35caSApple OSS Distributions 
340*c54f35caSApple OSS Distributions //*********************************************************************************
341*c54f35caSApple OSS Distributions // [public] PMinit
342*c54f35caSApple OSS Distributions //
343*c54f35caSApple OSS Distributions // Initialize power management.
344*c54f35caSApple OSS Distributions //*********************************************************************************
345*c54f35caSApple OSS Distributions 
346*c54f35caSApple OSS Distributions void
PMinit(void)347*c54f35caSApple OSS Distributions IOService::PMinit( void )
348*c54f35caSApple OSS Distributions {
349*c54f35caSApple OSS Distributions 	if (!initialized) {
350*c54f35caSApple OSS Distributions 		IOLockLock(gIOPMInitLock);
351*c54f35caSApple OSS Distributions 		if (!gIOPMInitialized) {
352*c54f35caSApple OSS Distributions 			gPlatform = getPlatform();
353*c54f35caSApple OSS Distributions 			gIOPMWorkLoop = IOWorkLoop::workLoop();
354*c54f35caSApple OSS Distributions 			if (gIOPMWorkLoop) {
355*c54f35caSApple OSS Distributions 				assert(OSDynamicCast(IOPMrootDomain, this));
356*c54f35caSApple OSS Distributions 				gIOPMRequestQueue = IOPMRequestQueue::create(
357*c54f35caSApple OSS Distributions 					this, OSMemberFunctionCast(IOPMRequestQueue::Action,
358*c54f35caSApple OSS Distributions 					this, &IOService::actionPMRequestQueue));
359*c54f35caSApple OSS Distributions 
360*c54f35caSApple OSS Distributions 				gIOPMReplyQueue = IOPMRequestQueue::create(
361*c54f35caSApple OSS Distributions 					this, OSMemberFunctionCast(IOPMRequestQueue::Action,
362*c54f35caSApple OSS Distributions 					this, &IOService::actionPMReplyQueue));
363*c54f35caSApple OSS Distributions 
364*c54f35caSApple OSS Distributions 				gIOPMWorkQueue = IOPMWorkQueue::create(this,
365*c54f35caSApple OSS Distributions 				    OSMemberFunctionCast(IOPMWorkQueue::Action, this,
366*c54f35caSApple OSS Distributions 				    &IOService::actionPMWorkQueueInvoke),
367*c54f35caSApple OSS Distributions 				    OSMemberFunctionCast(IOPMWorkQueue::Action, this,
368*c54f35caSApple OSS Distributions 				    &IOService::actionPMWorkQueueRetire));
369*c54f35caSApple OSS Distributions 
370*c54f35caSApple OSS Distributions 				gIOPMCompletionQueue = IOPMCompletionQueue::create(
371*c54f35caSApple OSS Distributions 					this, OSMemberFunctionCast(IOPMCompletionQueue::Action,
372*c54f35caSApple OSS Distributions 					this, &IOService::actionPMCompletionQueue));
373*c54f35caSApple OSS Distributions 
374*c54f35caSApple OSS Distributions 				if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
375*c54f35caSApple OSS Distributions 				    kIOReturnSuccess) {
376*c54f35caSApple OSS Distributions 					gIOPMRequestQueue->release();
377*c54f35caSApple OSS Distributions 					gIOPMRequestQueue = NULL;
378*c54f35caSApple OSS Distributions 				}
379*c54f35caSApple OSS Distributions 
380*c54f35caSApple OSS Distributions 				if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
381*c54f35caSApple OSS Distributions 				    kIOReturnSuccess) {
382*c54f35caSApple OSS Distributions 					gIOPMReplyQueue->release();
383*c54f35caSApple OSS Distributions 					gIOPMReplyQueue = NULL;
384*c54f35caSApple OSS Distributions 				}
385*c54f35caSApple OSS Distributions 
386*c54f35caSApple OSS Distributions 				if (gIOPMWorkLoop->addEventSource(gIOPMWorkQueue) !=
387*c54f35caSApple OSS Distributions 				    kIOReturnSuccess) {
388*c54f35caSApple OSS Distributions 					gIOPMWorkQueue->release();
389*c54f35caSApple OSS Distributions 					gIOPMWorkQueue = NULL;
390*c54f35caSApple OSS Distributions 				}
391*c54f35caSApple OSS Distributions 
392*c54f35caSApple OSS Distributions 				// Must be added after the work queue, which pushes request
393*c54f35caSApple OSS Distributions 				// to the completion queue without signaling the work loop.
394*c54f35caSApple OSS Distributions 				if (gIOPMWorkLoop->addEventSource(gIOPMCompletionQueue) !=
395*c54f35caSApple OSS Distributions 				    kIOReturnSuccess) {
396*c54f35caSApple OSS Distributions 					gIOPMCompletionQueue->release();
397*c54f35caSApple OSS Distributions 					gIOPMCompletionQueue = NULL;
398*c54f35caSApple OSS Distributions 				}
399*c54f35caSApple OSS Distributions 
400*c54f35caSApple OSS Distributions 				gIOPMPowerClientDevice =
401*c54f35caSApple OSS Distributions 				    OSSymbol::withCStringNoCopy( "DevicePowerState" );
402*c54f35caSApple OSS Distributions 
403*c54f35caSApple OSS Distributions 				gIOPMPowerClientDriver =
404*c54f35caSApple OSS Distributions 				    OSSymbol::withCStringNoCopy( "DriverPowerState" );
405*c54f35caSApple OSS Distributions 
406*c54f35caSApple OSS Distributions 				gIOPMPowerClientChildProxy =
407*c54f35caSApple OSS Distributions 				    OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
408*c54f35caSApple OSS Distributions 
409*c54f35caSApple OSS Distributions 				gIOPMPowerClientChildren =
410*c54f35caSApple OSS Distributions 				    OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
411*c54f35caSApple OSS Distributions 
412*c54f35caSApple OSS Distributions 				gIOPMPowerClientAdvisoryTickle =
413*c54f35caSApple OSS Distributions 				    OSSymbol::withCStringNoCopy( "AdvisoryTicklePowerState" );
414*c54f35caSApple OSS Distributions 
415*c54f35caSApple OSS Distributions 				gIOPMPowerClientRootDomain =
416*c54f35caSApple OSS Distributions 				    OSSymbol::withCStringNoCopy( "RootDomainPower" );
417*c54f35caSApple OSS Distributions 			}
418*c54f35caSApple OSS Distributions 
419*c54f35caSApple OSS Distributions 			if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMCompletionQueue) {
420*c54f35caSApple OSS Distributions 				gIOPMInitialized = true;
421*c54f35caSApple OSS Distributions 			}
422*c54f35caSApple OSS Distributions 
423*c54f35caSApple OSS Distributions #if (DEVELOPMENT || DEBUG)
424*c54f35caSApple OSS Distributions 			uint32_t setPowerStateLogMS = 0;
425*c54f35caSApple OSS Distributions 			if (PE_parse_boot_argn("setpowerstate_log", &setPowerStateLogMS, sizeof(setPowerStateLogMS))) {
426*c54f35caSApple OSS Distributions 				gIOPMSetPowerStateLogNS = setPowerStateLogMS * 1000000ULL;
427*c54f35caSApple OSS Distributions 			}
428*c54f35caSApple OSS Distributions #endif
429*c54f35caSApple OSS Distributions 		}
430*c54f35caSApple OSS Distributions 
431*c54f35caSApple OSS Distributions 		IOLockUnlock(gIOPMInitLock);
432*c54f35caSApple OSS Distributions 
433*c54f35caSApple OSS Distributions 		if (!gIOPMInitialized) {
434*c54f35caSApple OSS Distributions 			return;
435*c54f35caSApple OSS Distributions 		}
436*c54f35caSApple OSS Distributions 
437*c54f35caSApple OSS Distributions 		pwrMgt = new IOServicePM;
438*c54f35caSApple OSS Distributions 		pwrMgt->init();
439*c54f35caSApple OSS Distributions 		setProperty(kPwrMgtKey, pwrMgt);
440*c54f35caSApple OSS Distributions 
441*c54f35caSApple OSS Distributions 		queue_init(&pwrMgt->WorkChain);
442*c54f35caSApple OSS Distributions 		queue_init(&pwrMgt->RequestHead);
443*c54f35caSApple OSS Distributions 		queue_init(&pwrMgt->PMDriverCallQueue);
444*c54f35caSApple OSS Distributions 
445*c54f35caSApple OSS Distributions 		fOwner                      = this;
446*c54f35caSApple OSS Distributions 		fPMLock                     = IOLockAlloc();
447*c54f35caSApple OSS Distributions 		fInterestedDrivers          = new IOPMinformeeList;
448*c54f35caSApple OSS Distributions 		fInterestedDrivers->initialize();
449*c54f35caSApple OSS Distributions 		fDesiredPowerState          = kPowerStateZero;
450*c54f35caSApple OSS Distributions 		fDeviceDesire               = kPowerStateZero;
451*c54f35caSApple OSS Distributions 		fInitialPowerChange         = true;
452*c54f35caSApple OSS Distributions 		fInitialSetPowerState       = true;
453*c54f35caSApple OSS Distributions 		fPreviousRequestPowerFlags  = 0;
454*c54f35caSApple OSS Distributions 		fDeviceOverrideEnabled      = false;
455*c54f35caSApple OSS Distributions 		fMachineState               = kIOPM_Finished;
456*c54f35caSApple OSS Distributions 		fSavedMachineState          = kIOPM_BadMachineState;
457*c54f35caSApple OSS Distributions 		fIdleTimerMinPowerState     = kPowerStateZero;
458*c54f35caSApple OSS Distributions 		fActivityLock               = IOLockAlloc();
459*c54f35caSApple OSS Distributions 		fStrictTreeOrder            = false;
460*c54f35caSApple OSS Distributions 		fActivityTicklePowerState   = kInvalidTicklePowerState;
461*c54f35caSApple OSS Distributions 		fAdvisoryTicklePowerState   = kInvalidTicklePowerState;
462*c54f35caSApple OSS Distributions 		fControllingDriver          = NULL;
463*c54f35caSApple OSS Distributions 		fPowerStates                = NULL;
464*c54f35caSApple OSS Distributions 		fNumberOfPowerStates        = 0;
465*c54f35caSApple OSS Distributions 		fCurrentPowerState          = kPowerStateZero;
466*c54f35caSApple OSS Distributions 		fParentsCurrentPowerFlags   = 0;
467*c54f35caSApple OSS Distributions 		fMaxPowerState              = kPowerStateZero;
468*c54f35caSApple OSS Distributions 		fName                       = getName();
469*c54f35caSApple OSS Distributions 		fParentsKnowState           = false;
470*c54f35caSApple OSS Distributions 		fSerialNumber               = 0;
471*c54f35caSApple OSS Distributions 		fResponseArray              = NULL;
472*c54f35caSApple OSS Distributions 		fNotifyClientArray          = NULL;
473*c54f35caSApple OSS Distributions 		fCurrentPowerConsumption    = kIOPMUnknown;
474*c54f35caSApple OSS Distributions 		fOverrideMaxPowerState      = kIOPMPowerStateMax;
475*c54f35caSApple OSS Distributions 
476*c54f35caSApple OSS Distributions 		if (!gIOPMRootNode && (getParentEntry(gIOPowerPlane) == getRegistryRoot())) {
477*c54f35caSApple OSS Distributions 			gIOPMRootNode = this;
478*c54f35caSApple OSS Distributions 			fParentsKnowState = true;
479*c54f35caSApple OSS Distributions 		} else if (getProperty(kIOPMResetPowerStateOnWakeKey) == kOSBooleanTrue) {
480*c54f35caSApple OSS Distributions 			fResetPowerStateOnWake = true;
481*c54f35caSApple OSS Distributions 		}
482*c54f35caSApple OSS Distributions 
483*c54f35caSApple OSS Distributions 		if (IS_ROOT_DOMAIN) {
484*c54f35caSApple OSS Distributions 			fWatchdogTimer = thread_call_allocate(
485*c54f35caSApple OSS Distributions 				&IOService::watchdog_timer_expired, (thread_call_param_t)this);
486*c54f35caSApple OSS Distributions 			fWatchdogLock = IOLockAlloc();
487*c54f35caSApple OSS Distributions 
488*c54f35caSApple OSS Distributions 			fBlockedArray =  OSArray::withCapacity(4);
489*c54f35caSApple OSS Distributions 		}
490*c54f35caSApple OSS Distributions 
491*c54f35caSApple OSS Distributions 		fAckTimer = thread_call_allocate(
492*c54f35caSApple OSS Distributions 			&IOService::ack_timer_expired, (thread_call_param_t)this);
493*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
494*c54f35caSApple OSS Distributions 		fSettleTimer = thread_call_allocate(
495*c54f35caSApple OSS Distributions 			&settle_timer_expired, (thread_call_param_t)this);
496*c54f35caSApple OSS Distributions #endif
497*c54f35caSApple OSS Distributions 		fIdleTimer = thread_call_allocate(
498*c54f35caSApple OSS Distributions 			&idle_timer_expired, (thread_call_param_t)this);
499*c54f35caSApple OSS Distributions 		fDriverCallTimer = thread_call_allocate(
500*c54f35caSApple OSS Distributions 			&IOService::pmDriverCalloutTimer, (thread_call_param_t)this);
501*c54f35caSApple OSS Distributions 		fDriverCallEntry = thread_call_allocate(
502*c54f35caSApple OSS Distributions 			(thread_call_func_t) &IOService::pmDriverCallout, this);
503*c54f35caSApple OSS Distributions 		assert(fDriverCallEntry);
504*c54f35caSApple OSS Distributions 
505*c54f35caSApple OSS Distributions 		// Check for powerChangeDone override.
506*c54f35caSApple OSS Distributions 		if (OSMemberFunctionCast(void (*)(void),
507*c54f35caSApple OSS Distributions 		    getResourceService(), &IOService::powerChangeDone) !=
508*c54f35caSApple OSS Distributions 		    OSMemberFunctionCast(void (*)(void),
509*c54f35caSApple OSS Distributions 		    this, &IOService::powerChangeDone)) {
510*c54f35caSApple OSS Distributions 			fPCDFunctionOverride = true;
511*c54f35caSApple OSS Distributions 		}
512*c54f35caSApple OSS Distributions 
513*c54f35caSApple OSS Distributions #if PM_VARS_SUPPORT
514*c54f35caSApple OSS Distributions 		IOPMprot * prot = new IOPMprot;
515*c54f35caSApple OSS Distributions 		if (prot) {
516*c54f35caSApple OSS Distributions 			prot->init();
517*c54f35caSApple OSS Distributions 			prot->ourName = fName;
518*c54f35caSApple OSS Distributions 			prot->thePlatform = gPlatform;
519*c54f35caSApple OSS Distributions 			fPMVars = prot;
520*c54f35caSApple OSS Distributions 			pm_vars = prot;
521*c54f35caSApple OSS Distributions 		}
522*c54f35caSApple OSS Distributions #else
523*c54f35caSApple OSS Distributions 		pm_vars = (void *) (uintptr_t) true;
524*c54f35caSApple OSS Distributions #endif
525*c54f35caSApple OSS Distributions 
526*c54f35caSApple OSS Distributions 		initialized = true;
527*c54f35caSApple OSS Distributions 	}
528*c54f35caSApple OSS Distributions }
529*c54f35caSApple OSS Distributions 
530*c54f35caSApple OSS Distributions //*********************************************************************************
531*c54f35caSApple OSS Distributions // [private] PMfree
532*c54f35caSApple OSS Distributions //
533*c54f35caSApple OSS Distributions // Free the data created by PMinit. Only called from IOService::free().
534*c54f35caSApple OSS Distributions //*********************************************************************************
535*c54f35caSApple OSS Distributions 
536*c54f35caSApple OSS Distributions void
PMfree(void)537*c54f35caSApple OSS Distributions IOService::PMfree( void )
538*c54f35caSApple OSS Distributions {
539*c54f35caSApple OSS Distributions 	initialized = false;
540*c54f35caSApple OSS Distributions 	pm_vars = NULL;
541*c54f35caSApple OSS Distributions 
542*c54f35caSApple OSS Distributions 	if (pwrMgt) {
543*c54f35caSApple OSS Distributions 		assert(fMachineState == kIOPM_Finished);
544*c54f35caSApple OSS Distributions 		assert(fInsertInterestSet == NULL);
545*c54f35caSApple OSS Distributions 		assert(fRemoveInterestSet == NULL);
546*c54f35caSApple OSS Distributions 		assert(fNotifyChildArray == NULL);
547*c54f35caSApple OSS Distributions 		assert(queue_empty(&pwrMgt->RequestHead));
548*c54f35caSApple OSS Distributions 		assert(queue_empty(&fPMDriverCallQueue));
549*c54f35caSApple OSS Distributions 
550*c54f35caSApple OSS Distributions 		if (fWatchdogTimer) {
551*c54f35caSApple OSS Distributions 			thread_call_cancel(fWatchdogTimer);
552*c54f35caSApple OSS Distributions 			thread_call_free(fWatchdogTimer);
553*c54f35caSApple OSS Distributions 			fWatchdogTimer = NULL;
554*c54f35caSApple OSS Distributions 		}
555*c54f35caSApple OSS Distributions 
556*c54f35caSApple OSS Distributions 		if (fWatchdogLock) {
557*c54f35caSApple OSS Distributions 			IOLockFree(fWatchdogLock);
558*c54f35caSApple OSS Distributions 			fWatchdogLock = NULL;
559*c54f35caSApple OSS Distributions 		}
560*c54f35caSApple OSS Distributions 
561*c54f35caSApple OSS Distributions 		if (fBlockedArray) {
562*c54f35caSApple OSS Distributions 			fBlockedArray->release();
563*c54f35caSApple OSS Distributions 			fBlockedArray = NULL;
564*c54f35caSApple OSS Distributions 		}
565*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
566*c54f35caSApple OSS Distributions 		if (fSettleTimer) {
567*c54f35caSApple OSS Distributions 			thread_call_cancel(fSettleTimer);
568*c54f35caSApple OSS Distributions 			thread_call_free(fSettleTimer);
569*c54f35caSApple OSS Distributions 			fSettleTimer = NULL;
570*c54f35caSApple OSS Distributions 		}
571*c54f35caSApple OSS Distributions #endif
572*c54f35caSApple OSS Distributions 		if (fAckTimer) {
573*c54f35caSApple OSS Distributions 			thread_call_cancel(fAckTimer);
574*c54f35caSApple OSS Distributions 			thread_call_free(fAckTimer);
575*c54f35caSApple OSS Distributions 			fAckTimer = NULL;
576*c54f35caSApple OSS Distributions 		}
577*c54f35caSApple OSS Distributions 		if (fIdleTimer) {
578*c54f35caSApple OSS Distributions 			thread_call_cancel(fIdleTimer);
579*c54f35caSApple OSS Distributions 			thread_call_free(fIdleTimer);
580*c54f35caSApple OSS Distributions 			fIdleTimer = NULL;
581*c54f35caSApple OSS Distributions 		}
582*c54f35caSApple OSS Distributions 		if (fDriverCallEntry) {
583*c54f35caSApple OSS Distributions 			thread_call_free(fDriverCallEntry);
584*c54f35caSApple OSS Distributions 			fDriverCallEntry = NULL;
585*c54f35caSApple OSS Distributions 		}
586*c54f35caSApple OSS Distributions 		if (fDriverCallTimer) {
587*c54f35caSApple OSS Distributions 			thread_call_free(fDriverCallTimer);
588*c54f35caSApple OSS Distributions 			fDriverCallTimer = NULL;
589*c54f35caSApple OSS Distributions 		}
590*c54f35caSApple OSS Distributions 		if (fPMLock) {
591*c54f35caSApple OSS Distributions 			IOLockFree(fPMLock);
592*c54f35caSApple OSS Distributions 			fPMLock = NULL;
593*c54f35caSApple OSS Distributions 		}
594*c54f35caSApple OSS Distributions 		if (fActivityLock) {
595*c54f35caSApple OSS Distributions 			IOLockFree(fActivityLock);
596*c54f35caSApple OSS Distributions 			fActivityLock = NULL;
597*c54f35caSApple OSS Distributions 		}
598*c54f35caSApple OSS Distributions 		if (fInterestedDrivers) {
599*c54f35caSApple OSS Distributions 			fInterestedDrivers->release();
600*c54f35caSApple OSS Distributions 			fInterestedDrivers = NULL;
601*c54f35caSApple OSS Distributions 		}
602*c54f35caSApple OSS Distributions 		if (fDriverCallParamSlots && fDriverCallParamPtr) {
603*c54f35caSApple OSS Distributions 			IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
604*c54f35caSApple OSS Distributions 			fDriverCallParamPtr = NULL;
605*c54f35caSApple OSS Distributions 			fDriverCallParamSlots = 0;
606*c54f35caSApple OSS Distributions 		}
607*c54f35caSApple OSS Distributions 		if (fResponseArray) {
608*c54f35caSApple OSS Distributions 			fResponseArray->release();
609*c54f35caSApple OSS Distributions 			fResponseArray = NULL;
610*c54f35caSApple OSS Distributions 		}
611*c54f35caSApple OSS Distributions 		if (fNotifyClientArray) {
612*c54f35caSApple OSS Distributions 			fNotifyClientArray->release();
613*c54f35caSApple OSS Distributions 			fNotifyClientArray = NULL;
614*c54f35caSApple OSS Distributions 		}
615*c54f35caSApple OSS Distributions 		if (fReportBuf && fNumberOfPowerStates) {
616*c54f35caSApple OSS Distributions 			IOFreeData(fReportBuf, STATEREPORT_BUFSIZE(fNumberOfPowerStates));
617*c54f35caSApple OSS Distributions 			fReportBuf = NULL;
618*c54f35caSApple OSS Distributions 		}
619*c54f35caSApple OSS Distributions 		if (fPowerStates && fNumberOfPowerStates) {
620*c54f35caSApple OSS Distributions 			IODeleteData(fPowerStates, IOPMPSEntry, fNumberOfPowerStates);
621*c54f35caSApple OSS Distributions 			fNumberOfPowerStates = 0;
622*c54f35caSApple OSS Distributions 			fPowerStates = NULL;
623*c54f35caSApple OSS Distributions 		}
624*c54f35caSApple OSS Distributions 		if (fPowerClients) {
625*c54f35caSApple OSS Distributions 			fPowerClients->release();
626*c54f35caSApple OSS Distributions 			fPowerClients = NULL;
627*c54f35caSApple OSS Distributions 		}
628*c54f35caSApple OSS Distributions 
629*c54f35caSApple OSS Distributions #if PM_VARS_SUPPORT
630*c54f35caSApple OSS Distributions 		if (fPMVars) {
631*c54f35caSApple OSS Distributions 			fPMVars->release();
632*c54f35caSApple OSS Distributions 			fPMVars = NULL;
633*c54f35caSApple OSS Distributions 		}
634*c54f35caSApple OSS Distributions #endif
635*c54f35caSApple OSS Distributions 
636*c54f35caSApple OSS Distributions 		pwrMgt->release();
637*c54f35caSApple OSS Distributions 		pwrMgt = NULL;
638*c54f35caSApple OSS Distributions 	}
639*c54f35caSApple OSS Distributions }
640*c54f35caSApple OSS Distributions 
641*c54f35caSApple OSS Distributions void
PMDebug(uint32_t event,uintptr_t param1,uintptr_t param2)642*c54f35caSApple OSS Distributions IOService::PMDebug( uint32_t event, uintptr_t param1, uintptr_t param2 )
643*c54f35caSApple OSS Distributions {
644*c54f35caSApple OSS Distributions 	OUR_PMLog(event, param1, param2);
645*c54f35caSApple OSS Distributions }
646*c54f35caSApple OSS Distributions 
647*c54f35caSApple OSS Distributions //*********************************************************************************
648*c54f35caSApple OSS Distributions // [public] joinPMtree
649*c54f35caSApple OSS Distributions //
650*c54f35caSApple OSS Distributions // A policy-maker calls its nub here when initializing, to be attached into
651*c54f35caSApple OSS Distributions // the power management hierarchy.  The default function is to call the
652*c54f35caSApple OSS Distributions // platform expert, which knows how to do it.  This method is overridden
653*c54f35caSApple OSS Distributions // by a nub subclass which may either know how to do it, or may need to
654*c54f35caSApple OSS Distributions // take other action.
655*c54f35caSApple OSS Distributions //
656*c54f35caSApple OSS Distributions // This may be the only "power management" method used in a nub,
657*c54f35caSApple OSS Distributions // meaning it may not be initialized for power management.
658*c54f35caSApple OSS Distributions //*********************************************************************************
659*c54f35caSApple OSS Distributions 
660*c54f35caSApple OSS Distributions void
joinPMtree(IOService * driver)661*c54f35caSApple OSS Distributions IOService::joinPMtree( IOService * driver )
662*c54f35caSApple OSS Distributions {
663*c54f35caSApple OSS Distributions 	IOPlatformExpert *  platform;
664*c54f35caSApple OSS Distributions 
665*c54f35caSApple OSS Distributions 	platform = getPlatform();
666*c54f35caSApple OSS Distributions 	assert(platform != NULL);
667*c54f35caSApple OSS Distributions 	platform->PMRegisterDevice(this, driver);
668*c54f35caSApple OSS Distributions }
669*c54f35caSApple OSS Distributions 
670*c54f35caSApple OSS Distributions #ifndef __LP64__
671*c54f35caSApple OSS Distributions //*********************************************************************************
672*c54f35caSApple OSS Distributions // [deprecated] youAreRoot
673*c54f35caSApple OSS Distributions //
674*c54f35caSApple OSS Distributions // Power Managment is informing us that we are the root power domain.
675*c54f35caSApple OSS Distributions //*********************************************************************************
676*c54f35caSApple OSS Distributions 
677*c54f35caSApple OSS Distributions IOReturn
youAreRoot(void)678*c54f35caSApple OSS Distributions IOService::youAreRoot( void )
679*c54f35caSApple OSS Distributions {
680*c54f35caSApple OSS Distributions 	return IOPMNoErr;
681*c54f35caSApple OSS Distributions }
682*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
683*c54f35caSApple OSS Distributions 
684*c54f35caSApple OSS Distributions //*********************************************************************************
685*c54f35caSApple OSS Distributions // [public] PMstop
686*c54f35caSApple OSS Distributions //
687*c54f35caSApple OSS Distributions // Immediately stop driver callouts. Schedule an async stop request to detach
688*c54f35caSApple OSS Distributions // from power plane.
689*c54f35caSApple OSS Distributions //*********************************************************************************
690*c54f35caSApple OSS Distributions 
691*c54f35caSApple OSS Distributions void
PMstop(void)692*c54f35caSApple OSS Distributions IOService::PMstop( void )
693*c54f35caSApple OSS Distributions {
694*c54f35caSApple OSS Distributions 	IOPMRequest * request;
695*c54f35caSApple OSS Distributions 
696*c54f35caSApple OSS Distributions 	if (!initialized) {
697*c54f35caSApple OSS Distributions 		return;
698*c54f35caSApple OSS Distributions 	}
699*c54f35caSApple OSS Distributions 
700*c54f35caSApple OSS Distributions 	PM_LOCK();
701*c54f35caSApple OSS Distributions 
702*c54f35caSApple OSS Distributions 	if (fLockedFlags.PMStop) {
703*c54f35caSApple OSS Distributions 		PM_LOG2("%s: PMstop() already stopped\n", fName);
704*c54f35caSApple OSS Distributions 		PM_UNLOCK();
705*c54f35caSApple OSS Distributions 		return;
706*c54f35caSApple OSS Distributions 	}
707*c54f35caSApple OSS Distributions 
708*c54f35caSApple OSS Distributions 	// Inhibit future driver calls.
709*c54f35caSApple OSS Distributions 	fLockedFlags.PMStop = true;
710*c54f35caSApple OSS Distributions 
711*c54f35caSApple OSS Distributions 	// Wait for all prior driver calls to finish.
712*c54f35caSApple OSS Distributions 	waitForPMDriverCall();
713*c54f35caSApple OSS Distributions 
714*c54f35caSApple OSS Distributions 	PM_UNLOCK();
715*c54f35caSApple OSS Distributions 
716*c54f35caSApple OSS Distributions 	// The rest of the work is performed async.
717*c54f35caSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypePMStop );
718*c54f35caSApple OSS Distributions 	if (request) {
719*c54f35caSApple OSS Distributions 		PM_LOG2("%s: %p PMstop\n", getName(), OBFUSCATE(this));
720*c54f35caSApple OSS Distributions 		submitPMRequest( request );
721*c54f35caSApple OSS Distributions 	}
722*c54f35caSApple OSS Distributions }
723*c54f35caSApple OSS Distributions 
724*c54f35caSApple OSS Distributions //*********************************************************************************
725*c54f35caSApple OSS Distributions // [private] handlePMstop
726*c54f35caSApple OSS Distributions //
727*c54f35caSApple OSS Distributions // Disconnect the node from all parents and children in the power plane.
728*c54f35caSApple OSS Distributions //*********************************************************************************
729*c54f35caSApple OSS Distributions 
730*c54f35caSApple OSS Distributions void
handlePMstop(IOPMRequest * request)731*c54f35caSApple OSS Distributions IOService::handlePMstop( IOPMRequest * request )
732*c54f35caSApple OSS Distributions {
733*c54f35caSApple OSS Distributions 	OSIterator *        iter;
734*c54f35caSApple OSS Distributions 	OSObject *          next;
735*c54f35caSApple OSS Distributions 	IOPowerConnection * connection;
736*c54f35caSApple OSS Distributions 	IOService *         theChild;
737*c54f35caSApple OSS Distributions 	IOService *         theParent;
738*c54f35caSApple OSS Distributions 
739*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
740*c54f35caSApple OSS Distributions 	PM_LOG2("%s: %p %s start\n", getName(), OBFUSCATE(this), __FUNCTION__);
741*c54f35caSApple OSS Distributions 
742*c54f35caSApple OSS Distributions 	// remove driver from prevent system sleep lists
743*c54f35caSApple OSS Distributions 	getPMRootDomain()->updatePreventIdleSleepList(this, false);
744*c54f35caSApple OSS Distributions 	getPMRootDomain()->updatePreventSystemSleepList(this, false);
745*c54f35caSApple OSS Distributions 
746*c54f35caSApple OSS Distributions 	// remove the property
747*c54f35caSApple OSS Distributions 	removeProperty(kPwrMgtKey);
748*c54f35caSApple OSS Distributions 
749*c54f35caSApple OSS Distributions 	// detach parents
750*c54f35caSApple OSS Distributions 	iter = getParentIterator(gIOPowerPlane);
751*c54f35caSApple OSS Distributions 	if (iter) {
752*c54f35caSApple OSS Distributions 		while ((next = iter->getNextObject())) {
753*c54f35caSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, next))) {
754*c54f35caSApple OSS Distributions 				theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
755*c54f35caSApple OSS Distributions 				if (theParent) {
756*c54f35caSApple OSS Distributions 					theParent->removePowerChild(connection);
757*c54f35caSApple OSS Distributions 					theParent->release();
758*c54f35caSApple OSS Distributions 				}
759*c54f35caSApple OSS Distributions 			}
760*c54f35caSApple OSS Distributions 		}
761*c54f35caSApple OSS Distributions 		iter->release();
762*c54f35caSApple OSS Distributions 	}
763*c54f35caSApple OSS Distributions 
764*c54f35caSApple OSS Distributions 	// detach IOConnections
765*c54f35caSApple OSS Distributions 	detachAbove( gIOPowerPlane );
766*c54f35caSApple OSS Distributions 
767*c54f35caSApple OSS Distributions 	// no more power state changes
768*c54f35caSApple OSS Distributions 	fParentsKnowState = false;
769*c54f35caSApple OSS Distributions 
770*c54f35caSApple OSS Distributions 	// detach children
771*c54f35caSApple OSS Distributions 	iter = getChildIterator(gIOPowerPlane);
772*c54f35caSApple OSS Distributions 	if (iter) {
773*c54f35caSApple OSS Distributions 		while ((next = iter->getNextObject())) {
774*c54f35caSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, next))) {
775*c54f35caSApple OSS Distributions 				theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
776*c54f35caSApple OSS Distributions 				if (theChild) {
777*c54f35caSApple OSS Distributions 					// detach nub from child
778*c54f35caSApple OSS Distributions 					connection->detachFromChild(theChild, gIOPowerPlane);
779*c54f35caSApple OSS Distributions 					theChild->release();
780*c54f35caSApple OSS Distributions 				}
781*c54f35caSApple OSS Distributions 				// detach us from nub
782*c54f35caSApple OSS Distributions 				detachFromChild(connection, gIOPowerPlane);
783*c54f35caSApple OSS Distributions 			}
784*c54f35caSApple OSS Distributions 		}
785*c54f35caSApple OSS Distributions 		iter->release();
786*c54f35caSApple OSS Distributions 	}
787*c54f35caSApple OSS Distributions 
788*c54f35caSApple OSS Distributions 	// Remove all interested drivers from the list, including the power
789*c54f35caSApple OSS Distributions 	// controlling driver.
790*c54f35caSApple OSS Distributions 	//
791*c54f35caSApple OSS Distributions 	// Usually, the controlling driver and the policy-maker functionality
792*c54f35caSApple OSS Distributions 	// are implemented by the same object, and without the deregistration,
793*c54f35caSApple OSS Distributions 	// the object will be holding an extra retain on itself, and cannot
794*c54f35caSApple OSS Distributions 	// be freed.
795*c54f35caSApple OSS Distributions 
796*c54f35caSApple OSS Distributions 	if (fInterestedDrivers) {
797*c54f35caSApple OSS Distributions 		IOPMinformeeList *  list = fInterestedDrivers;
798*c54f35caSApple OSS Distributions 		IOPMinformee *      item;
799*c54f35caSApple OSS Distributions 
800*c54f35caSApple OSS Distributions 		PM_LOCK();
801*c54f35caSApple OSS Distributions 		while ((item = list->firstInList())) {
802*c54f35caSApple OSS Distributions 			list->removeFromList(item->whatObject);
803*c54f35caSApple OSS Distributions 		}
804*c54f35caSApple OSS Distributions 		PM_UNLOCK();
805*c54f35caSApple OSS Distributions 	}
806*c54f35caSApple OSS Distributions 
807*c54f35caSApple OSS Distributions 	// Clear idle period to prevent idleTimerExpired() from servicing
808*c54f35caSApple OSS Distributions 	// idle timer expirations.
809*c54f35caSApple OSS Distributions 
810*c54f35caSApple OSS Distributions 	fIdleTimerPeriod = 0;
811*c54f35caSApple OSS Distributions 	if (fIdleTimer && thread_call_cancel(fIdleTimer)) {
812*c54f35caSApple OSS Distributions 		release();
813*c54f35caSApple OSS Distributions 	}
814*c54f35caSApple OSS Distributions 
815*c54f35caSApple OSS Distributions 	PM_LOG2("%s: %p %s done\n", getName(), OBFUSCATE(this), __FUNCTION__);
816*c54f35caSApple OSS Distributions }
817*c54f35caSApple OSS Distributions 
818*c54f35caSApple OSS Distributions //*********************************************************************************
819*c54f35caSApple OSS Distributions // [public] addPowerChild
820*c54f35caSApple OSS Distributions //
821*c54f35caSApple OSS Distributions // Power Management is informing us who our children are.
822*c54f35caSApple OSS Distributions //*********************************************************************************
823*c54f35caSApple OSS Distributions 
824*c54f35caSApple OSS Distributions IOReturn
addPowerChild(IOService * child)825*c54f35caSApple OSS Distributions IOService::addPowerChild( IOService * child )
826*c54f35caSApple OSS Distributions {
827*c54f35caSApple OSS Distributions 	IOPowerConnection * connection  = NULL;
828*c54f35caSApple OSS Distributions 	IOPMRequest *       requests[3] = {NULL, NULL, NULL};
829*c54f35caSApple OSS Distributions 	OSIterator *        iter;
830*c54f35caSApple OSS Distributions 	bool                ok = true;
831*c54f35caSApple OSS Distributions 
832*c54f35caSApple OSS Distributions 	if (!child) {
833*c54f35caSApple OSS Distributions 		return kIOReturnBadArgument;
834*c54f35caSApple OSS Distributions 	}
835*c54f35caSApple OSS Distributions 
836*c54f35caSApple OSS Distributions 	if (!initialized || !child->initialized) {
837*c54f35caSApple OSS Distributions 		return IOPMNotYetInitialized;
838*c54f35caSApple OSS Distributions 	}
839*c54f35caSApple OSS Distributions 
840*c54f35caSApple OSS Distributions 	OUR_PMLog( kPMLogAddChild, (uintptr_t) child, 0 );
841*c54f35caSApple OSS Distributions 
842*c54f35caSApple OSS Distributions 	do {
843*c54f35caSApple OSS Distributions 		// Is this child already one of our children?
844*c54f35caSApple OSS Distributions 
845*c54f35caSApple OSS Distributions 		iter = child->getParentIterator( gIOPowerPlane );
846*c54f35caSApple OSS Distributions 		if (iter) {
847*c54f35caSApple OSS Distributions 			IORegistryEntry *   entry;
848*c54f35caSApple OSS Distributions 			OSObject *          next;
849*c54f35caSApple OSS Distributions 
850*c54f35caSApple OSS Distributions 			while ((next = iter->getNextObject())) {
851*c54f35caSApple OSS Distributions 				if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
852*c54f35caSApple OSS Distributions 				    isChild(entry, gIOPowerPlane)) {
853*c54f35caSApple OSS Distributions 					ok = false;
854*c54f35caSApple OSS Distributions 					break;
855*c54f35caSApple OSS Distributions 				}
856*c54f35caSApple OSS Distributions 			}
857*c54f35caSApple OSS Distributions 			iter->release();
858*c54f35caSApple OSS Distributions 		}
859*c54f35caSApple OSS Distributions 		if (!ok) {
860*c54f35caSApple OSS Distributions 			PM_LOG2("%s: %s (%p) is already a child\n",
861*c54f35caSApple OSS Distributions 			    getName(), child->getName(), OBFUSCATE(child));
862*c54f35caSApple OSS Distributions 			break;
863*c54f35caSApple OSS Distributions 		}
864*c54f35caSApple OSS Distributions 
865*c54f35caSApple OSS Distributions 		// Add the child to the power plane immediately, but the
866*c54f35caSApple OSS Distributions 		// joining connection is marked as not ready.
867*c54f35caSApple OSS Distributions 		// We want the child to appear in the power plane before
868*c54f35caSApple OSS Distributions 		// returning to the caller, but don't want the caller to
869*c54f35caSApple OSS Distributions 		// block on the PM work loop.
870*c54f35caSApple OSS Distributions 
871*c54f35caSApple OSS Distributions 		connection = new IOPowerConnection;
872*c54f35caSApple OSS Distributions 		if (!connection) {
873*c54f35caSApple OSS Distributions 			break;
874*c54f35caSApple OSS Distributions 		}
875*c54f35caSApple OSS Distributions 
876*c54f35caSApple OSS Distributions 		// Create a chain of PM requests to perform the bottom-half
877*c54f35caSApple OSS Distributions 		// work from the PM work loop.
878*c54f35caSApple OSS Distributions 
879*c54f35caSApple OSS Distributions 		requests[0] = acquirePMRequest(
880*c54f35caSApple OSS Distributions 			/* target */ this,
881*c54f35caSApple OSS Distributions 			/* type */ kIOPMRequestTypeAddPowerChild1 );
882*c54f35caSApple OSS Distributions 
883*c54f35caSApple OSS Distributions 		requests[1] = acquirePMRequest(
884*c54f35caSApple OSS Distributions 			/* target */ child,
885*c54f35caSApple OSS Distributions 			/* type */ kIOPMRequestTypeAddPowerChild2 );
886*c54f35caSApple OSS Distributions 
887*c54f35caSApple OSS Distributions 		requests[2] = acquirePMRequest(
888*c54f35caSApple OSS Distributions 			/* target */ this,
889*c54f35caSApple OSS Distributions 			/* type */ kIOPMRequestTypeAddPowerChild3 );
890*c54f35caSApple OSS Distributions 
891*c54f35caSApple OSS Distributions 		if (!requests[0] || !requests[1] || !requests[2]) {
892*c54f35caSApple OSS Distributions 			break;
893*c54f35caSApple OSS Distributions 		}
894*c54f35caSApple OSS Distributions 
895*c54f35caSApple OSS Distributions 		requests[0]->attachNextRequest( requests[1] );
896*c54f35caSApple OSS Distributions 		requests[1]->attachNextRequest( requests[2] );
897*c54f35caSApple OSS Distributions 
898*c54f35caSApple OSS Distributions 		connection->init();
899*c54f35caSApple OSS Distributions 		connection->start(this);
900*c54f35caSApple OSS Distributions 		connection->setAwaitingAck(false);
901*c54f35caSApple OSS Distributions 		connection->setReadyFlag(false);
902*c54f35caSApple OSS Distributions 
903*c54f35caSApple OSS Distributions 		attachToChild( connection, gIOPowerPlane );
904*c54f35caSApple OSS Distributions 		connection->attachToChild( child, gIOPowerPlane );
905*c54f35caSApple OSS Distributions 
906*c54f35caSApple OSS Distributions 		// connection needs to be released
907*c54f35caSApple OSS Distributions 		requests[0]->fArg0 = connection;
908*c54f35caSApple OSS Distributions 		requests[1]->fArg0 = connection;
909*c54f35caSApple OSS Distributions 		requests[2]->fArg0 = connection;
910*c54f35caSApple OSS Distributions 
911*c54f35caSApple OSS Distributions 		submitPMRequests( requests, 3 );
912*c54f35caSApple OSS Distributions 		return kIOReturnSuccess;
913*c54f35caSApple OSS Distributions 	}while (false);
914*c54f35caSApple OSS Distributions 
915*c54f35caSApple OSS Distributions 	if (connection) {
916*c54f35caSApple OSS Distributions 		connection->release();
917*c54f35caSApple OSS Distributions 	}
918*c54f35caSApple OSS Distributions 	if (requests[0]) {
919*c54f35caSApple OSS Distributions 		releasePMRequest(requests[0]);
920*c54f35caSApple OSS Distributions 	}
921*c54f35caSApple OSS Distributions 	if (requests[1]) {
922*c54f35caSApple OSS Distributions 		releasePMRequest(requests[1]);
923*c54f35caSApple OSS Distributions 	}
924*c54f35caSApple OSS Distributions 	if (requests[2]) {
925*c54f35caSApple OSS Distributions 		releasePMRequest(requests[2]);
926*c54f35caSApple OSS Distributions 	}
927*c54f35caSApple OSS Distributions 
928*c54f35caSApple OSS Distributions 	// Silent failure, to prevent platform drivers from adding the child
929*c54f35caSApple OSS Distributions 	// to the root domain.
930*c54f35caSApple OSS Distributions 
931*c54f35caSApple OSS Distributions 	return kIOReturnSuccess;
932*c54f35caSApple OSS Distributions }
933*c54f35caSApple OSS Distributions 
934*c54f35caSApple OSS Distributions //*********************************************************************************
935*c54f35caSApple OSS Distributions // [private] addPowerChild1
936*c54f35caSApple OSS Distributions //
937*c54f35caSApple OSS Distributions // Step 1/3 of adding a power child. Called on the power parent.
938*c54f35caSApple OSS Distributions //*********************************************************************************
939*c54f35caSApple OSS Distributions 
940*c54f35caSApple OSS Distributions void
addPowerChild1(IOPMRequest * request)941*c54f35caSApple OSS Distributions IOService::addPowerChild1( IOPMRequest * request )
942*c54f35caSApple OSS Distributions {
943*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex tempDesire = kPowerStateZero;
944*c54f35caSApple OSS Distributions 
945*c54f35caSApple OSS Distributions 	// Make us temporary usable before adding the child.
946*c54f35caSApple OSS Distributions 
947*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
948*c54f35caSApple OSS Distributions 	OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, 0 );
949*c54f35caSApple OSS Distributions 
950*c54f35caSApple OSS Distributions 	if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState) {
951*c54f35caSApple OSS Distributions 		tempDesire = fHighestPowerState;
952*c54f35caSApple OSS Distributions 	}
953*c54f35caSApple OSS Distributions 
954*c54f35caSApple OSS Distributions 	if ((tempDesire != kPowerStateZero) &&
955*c54f35caSApple OSS Distributions 	    (IS_PM_ROOT || (StateOrder(fMaxPowerState) >= StateOrder(tempDesire)))) {
956*c54f35caSApple OSS Distributions 		adjustPowerState(tempDesire);
957*c54f35caSApple OSS Distributions 	}
958*c54f35caSApple OSS Distributions }
959*c54f35caSApple OSS Distributions 
960*c54f35caSApple OSS Distributions //*********************************************************************************
961*c54f35caSApple OSS Distributions // [private] addPowerChild2
962*c54f35caSApple OSS Distributions //
963*c54f35caSApple OSS Distributions // Step 2/3 of adding a power child. Called on the joining child.
964*c54f35caSApple OSS Distributions // Execution blocked behind addPowerChild1.
965*c54f35caSApple OSS Distributions //*********************************************************************************
966*c54f35caSApple OSS Distributions 
967*c54f35caSApple OSS Distributions void
addPowerChild2(IOPMRequest * request)968*c54f35caSApple OSS Distributions IOService::addPowerChild2( IOPMRequest * request )
969*c54f35caSApple OSS Distributions {
970*c54f35caSApple OSS Distributions 	IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
971*c54f35caSApple OSS Distributions 	IOService *         parent;
972*c54f35caSApple OSS Distributions 	IOPMPowerFlags      powerFlags;
973*c54f35caSApple OSS Distributions 	bool                knowsState;
974*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex powerState;
975*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex tempDesire;
976*c54f35caSApple OSS Distributions 
977*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
978*c54f35caSApple OSS Distributions 	parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
979*c54f35caSApple OSS Distributions 
980*c54f35caSApple OSS Distributions 	if (!parent || !inPlane(gIOPowerPlane)) {
981*c54f35caSApple OSS Distributions 		PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
982*c54f35caSApple OSS Distributions 		return;
983*c54f35caSApple OSS Distributions 	}
984*c54f35caSApple OSS Distributions 
985*c54f35caSApple OSS Distributions 	// Parent will be waiting for us to complete this stage.
986*c54f35caSApple OSS Distributions 	// It is safe to directly access parent's vars.
987*c54f35caSApple OSS Distributions 
988*c54f35caSApple OSS Distributions 	knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
989*c54f35caSApple OSS Distributions 	powerState = parent->fCurrentPowerState;
990*c54f35caSApple OSS Distributions 
991*c54f35caSApple OSS Distributions 	if (knowsState) {
992*c54f35caSApple OSS Distributions 		powerFlags = parent->fPowerStates[powerState].outputPowerFlags;
993*c54f35caSApple OSS Distributions 	} else {
994*c54f35caSApple OSS Distributions 		powerFlags = 0;
995*c54f35caSApple OSS Distributions 	}
996*c54f35caSApple OSS Distributions 
997*c54f35caSApple OSS Distributions 	// Set our power parent.
998*c54f35caSApple OSS Distributions 
999*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
1000*c54f35caSApple OSS Distributions 
1001*c54f35caSApple OSS Distributions 	setParentInfo( powerFlags, connection, knowsState );
1002*c54f35caSApple OSS Distributions 
1003*c54f35caSApple OSS Distributions 	connection->setReadyFlag(true);
1004*c54f35caSApple OSS Distributions 
1005*c54f35caSApple OSS Distributions 	if (fControllingDriver && fParentsKnowState) {
1006*c54f35caSApple OSS Distributions 		fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1007*c54f35caSApple OSS Distributions 		// initially change into the state we are already in
1008*c54f35caSApple OSS Distributions 		tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1009*c54f35caSApple OSS Distributions 		fPreviousRequestPowerFlags = (IOPMPowerFlags)(-1);
1010*c54f35caSApple OSS Distributions 		adjustPowerState(tempDesire);
1011*c54f35caSApple OSS Distributions 	}
1012*c54f35caSApple OSS Distributions }
1013*c54f35caSApple OSS Distributions 
1014*c54f35caSApple OSS Distributions //*********************************************************************************
1015*c54f35caSApple OSS Distributions // [private] addPowerChild3
1016*c54f35caSApple OSS Distributions //
1017*c54f35caSApple OSS Distributions // Step 3/3 of adding a power child. Called on the parent.
1018*c54f35caSApple OSS Distributions // Execution blocked behind addPowerChild2.
1019*c54f35caSApple OSS Distributions //*********************************************************************************
1020*c54f35caSApple OSS Distributions 
1021*c54f35caSApple OSS Distributions void
addPowerChild3(IOPMRequest * request)1022*c54f35caSApple OSS Distributions IOService::addPowerChild3( IOPMRequest * request )
1023*c54f35caSApple OSS Distributions {
1024*c54f35caSApple OSS Distributions 	IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
1025*c54f35caSApple OSS Distributions 	IOService *         child;
1026*c54f35caSApple OSS Distributions 	IOPMrootDomain *    rootDomain = getPMRootDomain();
1027*c54f35caSApple OSS Distributions 
1028*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1029*c54f35caSApple OSS Distributions 	child = (IOService *) connection->getChildEntry(gIOPowerPlane);
1030*c54f35caSApple OSS Distributions 
1031*c54f35caSApple OSS Distributions 	if (child && inPlane(gIOPowerPlane)) {
1032*c54f35caSApple OSS Distributions 		if ((this != rootDomain) && child->getProperty("IOPMStrictTreeOrder")) {
1033*c54f35caSApple OSS Distributions 			PM_LOG1("%s: strict PM order enforced\n", getName());
1034*c54f35caSApple OSS Distributions 			fStrictTreeOrder = true;
1035*c54f35caSApple OSS Distributions 		}
1036*c54f35caSApple OSS Distributions 
1037*c54f35caSApple OSS Distributions 		if (rootDomain) {
1038*c54f35caSApple OSS Distributions 			rootDomain->joinAggressiveness( child );
1039*c54f35caSApple OSS Distributions 		}
1040*c54f35caSApple OSS Distributions 	} else {
1041*c54f35caSApple OSS Distributions 		PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
1042*c54f35caSApple OSS Distributions 	}
1043*c54f35caSApple OSS Distributions 
1044*c54f35caSApple OSS Distributions 	connection->release();
1045*c54f35caSApple OSS Distributions }
1046*c54f35caSApple OSS Distributions 
1047*c54f35caSApple OSS Distributions #ifndef __LP64__
1048*c54f35caSApple OSS Distributions //*********************************************************************************
1049*c54f35caSApple OSS Distributions // [deprecated] setPowerParent
1050*c54f35caSApple OSS Distributions //
1051*c54f35caSApple OSS Distributions // Power Management is informing us who our parent is.
1052*c54f35caSApple OSS Distributions // If we have a controlling driver, find out, given our newly-informed
1053*c54f35caSApple OSS Distributions // power domain state, what state it would be in, and then tell it
1054*c54f35caSApple OSS Distributions // to assume that state.
1055*c54f35caSApple OSS Distributions //*********************************************************************************
1056*c54f35caSApple OSS Distributions 
1057*c54f35caSApple OSS Distributions IOReturn
setPowerParent(IOPowerConnection * theParent,bool stateKnown,IOPMPowerFlags powerFlags)1058*c54f35caSApple OSS Distributions IOService::setPowerParent(
1059*c54f35caSApple OSS Distributions 	IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
1060*c54f35caSApple OSS Distributions {
1061*c54f35caSApple OSS Distributions 	return kIOReturnUnsupported;
1062*c54f35caSApple OSS Distributions }
1063*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
1064*c54f35caSApple OSS Distributions 
1065*c54f35caSApple OSS Distributions //*********************************************************************************
1066*c54f35caSApple OSS Distributions // [public] removePowerChild
1067*c54f35caSApple OSS Distributions //
1068*c54f35caSApple OSS Distributions // Called on a parent whose child is being removed by PMstop().
1069*c54f35caSApple OSS Distributions //*********************************************************************************
1070*c54f35caSApple OSS Distributions 
1071*c54f35caSApple OSS Distributions IOReturn
removePowerChild(IOPowerConnection * theNub)1072*c54f35caSApple OSS Distributions IOService::removePowerChild( IOPowerConnection * theNub )
1073*c54f35caSApple OSS Distributions {
1074*c54f35caSApple OSS Distributions 	IORegistryEntry *   theChild;
1075*c54f35caSApple OSS Distributions 
1076*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1077*c54f35caSApple OSS Distributions 	OUR_PMLog( kPMLogRemoveChild, 0, 0 );
1078*c54f35caSApple OSS Distributions 
1079*c54f35caSApple OSS Distributions 	theNub->retain();
1080*c54f35caSApple OSS Distributions 
1081*c54f35caSApple OSS Distributions 	// detach nub from child
1082*c54f35caSApple OSS Distributions 	theChild = theNub->copyChildEntry(gIOPowerPlane);
1083*c54f35caSApple OSS Distributions 	if (theChild) {
1084*c54f35caSApple OSS Distributions 		theNub->detachFromChild(theChild, gIOPowerPlane);
1085*c54f35caSApple OSS Distributions 		theChild->release();
1086*c54f35caSApple OSS Distributions 	}
1087*c54f35caSApple OSS Distributions 	// detach from the nub
1088*c54f35caSApple OSS Distributions 	detachFromChild(theNub, gIOPowerPlane);
1089*c54f35caSApple OSS Distributions 
1090*c54f35caSApple OSS Distributions 	// Are we awaiting an ack from this child?
1091*c54f35caSApple OSS Distributions 	if (theNub->getAwaitingAck()) {
1092*c54f35caSApple OSS Distributions 		// yes, pretend we got one
1093*c54f35caSApple OSS Distributions 		theNub->setAwaitingAck(false);
1094*c54f35caSApple OSS Distributions 		if (fHeadNotePendingAcks != 0) {
1095*c54f35caSApple OSS Distributions 			// that's one fewer ack to worry about
1096*c54f35caSApple OSS Distributions 			fHeadNotePendingAcks--;
1097*c54f35caSApple OSS Distributions 
1098*c54f35caSApple OSS Distributions 			// is that the last?
1099*c54f35caSApple OSS Distributions 			if (fHeadNotePendingAcks == 0) {
1100*c54f35caSApple OSS Distributions 				stop_ack_timer();
1101*c54f35caSApple OSS Distributions 				getPMRootDomain()->reset_watchdog_timer(this, 0);
1102*c54f35caSApple OSS Distributions 
1103*c54f35caSApple OSS Distributions 				// This parent may have a request in the work queue that is
1104*c54f35caSApple OSS Distributions 				// blocked on fHeadNotePendingAcks=0. And removePowerChild()
1105*c54f35caSApple OSS Distributions 				// is called while executing the child's PMstop request so they
1106*c54f35caSApple OSS Distributions 				// can occur simultaneously. IOPMWorkQueue::checkForWork() must
1107*c54f35caSApple OSS Distributions 				// restart and check all request queues again.
1108*c54f35caSApple OSS Distributions 
1109*c54f35caSApple OSS Distributions 				gIOPMWorkQueue->incrementProducerCount();
1110*c54f35caSApple OSS Distributions 			}
1111*c54f35caSApple OSS Distributions 		}
1112*c54f35caSApple OSS Distributions 	}
1113*c54f35caSApple OSS Distributions 
1114*c54f35caSApple OSS Distributions 	theNub->release();
1115*c54f35caSApple OSS Distributions 
1116*c54f35caSApple OSS Distributions 	// A child has gone away, re-scan children desires and clamp bits.
1117*c54f35caSApple OSS Distributions 	// The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1118*c54f35caSApple OSS Distributions 
1119*c54f35caSApple OSS Distributions 	if (!fAdjustPowerScheduled) {
1120*c54f35caSApple OSS Distributions 		IOPMRequest * request;
1121*c54f35caSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1122*c54f35caSApple OSS Distributions 		if (request) {
1123*c54f35caSApple OSS Distributions 			submitPMRequest( request );
1124*c54f35caSApple OSS Distributions 			fAdjustPowerScheduled = true;
1125*c54f35caSApple OSS Distributions 		}
1126*c54f35caSApple OSS Distributions 	}
1127*c54f35caSApple OSS Distributions 
1128*c54f35caSApple OSS Distributions 	return IOPMNoErr;
1129*c54f35caSApple OSS Distributions }
1130*c54f35caSApple OSS Distributions 
1131*c54f35caSApple OSS Distributions //*********************************************************************************
1132*c54f35caSApple OSS Distributions // [public] registerPowerDriver
1133*c54f35caSApple OSS Distributions //
1134*c54f35caSApple OSS Distributions // A driver has called us volunteering to control power to our device.
1135*c54f35caSApple OSS Distributions //*********************************************************************************
1136*c54f35caSApple OSS Distributions 
1137*c54f35caSApple OSS Distributions IOReturn
registerPowerDriver(IOService * powerDriver,IOPMPowerState * powerStates,unsigned long numberOfStates)1138*c54f35caSApple OSS Distributions IOService::registerPowerDriver(
1139*c54f35caSApple OSS Distributions 	IOService *         powerDriver,
1140*c54f35caSApple OSS Distributions 	IOPMPowerState *    powerStates,
1141*c54f35caSApple OSS Distributions 	unsigned long       numberOfStates )
1142*c54f35caSApple OSS Distributions {
1143*c54f35caSApple OSS Distributions 	IOPMRequest *       request;
1144*c54f35caSApple OSS Distributions 	IOPMPSEntry *       powerStatesCopy = NULL;
1145*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex stateOrder;
1146*c54f35caSApple OSS Distributions 	IOReturn            error = kIOReturnSuccess;
1147*c54f35caSApple OSS Distributions 
1148*c54f35caSApple OSS Distributions 	if (!initialized) {
1149*c54f35caSApple OSS Distributions 		return IOPMNotYetInitialized;
1150*c54f35caSApple OSS Distributions 	}
1151*c54f35caSApple OSS Distributions 
1152*c54f35caSApple OSS Distributions 	if (!powerStates || (numberOfStates < 2)) {
1153*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1154*c54f35caSApple OSS Distributions 		return kIOReturnBadArgument;
1155*c54f35caSApple OSS Distributions 	}
1156*c54f35caSApple OSS Distributions 
1157*c54f35caSApple OSS Distributions 	if (!powerDriver || !powerDriver->initialized) {
1158*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1159*c54f35caSApple OSS Distributions 		return kIOReturnBadArgument;
1160*c54f35caSApple OSS Distributions 	}
1161*c54f35caSApple OSS Distributions 
1162*c54f35caSApple OSS Distributions 	if (powerStates[0].version > kIOPMPowerStateVersion2) {
1163*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1164*c54f35caSApple OSS Distributions 		return kIOReturnBadArgument;
1165*c54f35caSApple OSS Distributions 	}
1166*c54f35caSApple OSS Distributions 
1167*c54f35caSApple OSS Distributions 	do {
1168*c54f35caSApple OSS Distributions 		// Make a copy of the supplied power state array.
1169*c54f35caSApple OSS Distributions 		powerStatesCopy = IONewData(IOPMPSEntry, numberOfStates);
1170*c54f35caSApple OSS Distributions 		if (!powerStatesCopy) {
1171*c54f35caSApple OSS Distributions 			error = kIOReturnNoMemory;
1172*c54f35caSApple OSS Distributions 			break;
1173*c54f35caSApple OSS Distributions 		}
1174*c54f35caSApple OSS Distributions 
1175*c54f35caSApple OSS Distributions 		// Initialize to bogus values
1176*c54f35caSApple OSS Distributions 		for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++) {
1177*c54f35caSApple OSS Distributions 			powerStatesCopy[i].stateOrderToIndex = kIOPMPowerStateMax;
1178*c54f35caSApple OSS Distributions 		}
1179*c54f35caSApple OSS Distributions 
1180*c54f35caSApple OSS Distributions 		for (uint32_t i = 0; i < numberOfStates; i++) {
1181*c54f35caSApple OSS Distributions 			powerStatesCopy[i].capabilityFlags  = powerStates[i].capabilityFlags;
1182*c54f35caSApple OSS Distributions 			powerStatesCopy[i].outputPowerFlags = powerStates[i].outputPowerCharacter;
1183*c54f35caSApple OSS Distributions 			powerStatesCopy[i].inputPowerFlags  = powerStates[i].inputPowerRequirement;
1184*c54f35caSApple OSS Distributions 			powerStatesCopy[i].staticPower      = powerStates[i].staticPower;
1185*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
1186*c54f35caSApple OSS Distributions 			powerStatesCopy[i].settleUpTime     = powerStates[i].settleUpTime;
1187*c54f35caSApple OSS Distributions 			powerStatesCopy[i].settleDownTime   = powerStates[i].settleDownTime;
1188*c54f35caSApple OSS Distributions #endif
1189*c54f35caSApple OSS Distributions 			if (powerStates[i].version >= kIOPMPowerStateVersion2) {
1190*c54f35caSApple OSS Distributions 				stateOrder = powerStates[i].stateOrder;
1191*c54f35caSApple OSS Distributions 			} else {
1192*c54f35caSApple OSS Distributions 				stateOrder = i;
1193*c54f35caSApple OSS Distributions 			}
1194*c54f35caSApple OSS Distributions 
1195*c54f35caSApple OSS Distributions 			if (stateOrder < numberOfStates) {
1196*c54f35caSApple OSS Distributions 				powerStatesCopy[i].stateOrder = stateOrder;
1197*c54f35caSApple OSS Distributions 				powerStatesCopy[stateOrder].stateOrderToIndex = i;
1198*c54f35caSApple OSS Distributions 			}
1199*c54f35caSApple OSS Distributions 		}
1200*c54f35caSApple OSS Distributions 
1201*c54f35caSApple OSS Distributions 		for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++) {
1202*c54f35caSApple OSS Distributions 			if (powerStatesCopy[i].stateOrderToIndex == kIOPMPowerStateMax) {
1203*c54f35caSApple OSS Distributions 				// power state order missing
1204*c54f35caSApple OSS Distributions 				error = kIOReturnBadArgument;
1205*c54f35caSApple OSS Distributions 				break;
1206*c54f35caSApple OSS Distributions 			}
1207*c54f35caSApple OSS Distributions 		}
1208*c54f35caSApple OSS Distributions 		if (kIOReturnSuccess != error) {
1209*c54f35caSApple OSS Distributions 			break;
1210*c54f35caSApple OSS Distributions 		}
1211*c54f35caSApple OSS Distributions 
1212*c54f35caSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1213*c54f35caSApple OSS Distributions 		if (!request) {
1214*c54f35caSApple OSS Distributions 			error = kIOReturnNoMemory;
1215*c54f35caSApple OSS Distributions 			break;
1216*c54f35caSApple OSS Distributions 		}
1217*c54f35caSApple OSS Distributions 
1218*c54f35caSApple OSS Distributions 		powerDriver->retain();
1219*c54f35caSApple OSS Distributions 		request->fArg0 = (void *) powerDriver;
1220*c54f35caSApple OSS Distributions 		request->fArg1 = (void *) powerStatesCopy;
1221*c54f35caSApple OSS Distributions 		request->fArg2 = (void *) numberOfStates;
1222*c54f35caSApple OSS Distributions 
1223*c54f35caSApple OSS Distributions 		submitPMRequest( request );
1224*c54f35caSApple OSS Distributions 		return kIOReturnSuccess;
1225*c54f35caSApple OSS Distributions 	}while (false);
1226*c54f35caSApple OSS Distributions 
1227*c54f35caSApple OSS Distributions 	if (powerStatesCopy) {
1228*c54f35caSApple OSS Distributions 		IODeleteData(powerStatesCopy, IOPMPSEntry, numberOfStates);
1229*c54f35caSApple OSS Distributions 	}
1230*c54f35caSApple OSS Distributions 
1231*c54f35caSApple OSS Distributions 	return error;
1232*c54f35caSApple OSS Distributions }
1233*c54f35caSApple OSS Distributions 
1234*c54f35caSApple OSS Distributions //*********************************************************************************
1235*c54f35caSApple OSS Distributions // [private] handleRegisterPowerDriver
1236*c54f35caSApple OSS Distributions //*********************************************************************************
1237*c54f35caSApple OSS Distributions 
1238*c54f35caSApple OSS Distributions void
handleRegisterPowerDriver(IOPMRequest * request)1239*c54f35caSApple OSS Distributions IOService::handleRegisterPowerDriver( IOPMRequest * request )
1240*c54f35caSApple OSS Distributions {
1241*c54f35caSApple OSS Distributions 	IOService *           powerDriver    = (IOService *)   request->fArg0;
1242*c54f35caSApple OSS Distributions 	IOPMPSEntry *         powerStates    = (IOPMPSEntry *) request->fArg1;
1243*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex   numberOfStates = (IOPMPowerStateIndex) request->fArg2;
1244*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex   i, stateIndex;
1245*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex   lowestPowerState;
1246*c54f35caSApple OSS Distributions 	IOService *           root;
1247*c54f35caSApple OSS Distributions 	OSIterator *          iter;
1248*c54f35caSApple OSS Distributions 
1249*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1250*c54f35caSApple OSS Distributions 	assert(powerStates);
1251*c54f35caSApple OSS Distributions 	assert(powerDriver);
1252*c54f35caSApple OSS Distributions 	assert(numberOfStates > 1);
1253*c54f35caSApple OSS Distributions 
1254*c54f35caSApple OSS Distributions 	if (!fNumberOfPowerStates) {
1255*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogControllingDriver, numberOfStates, kIOPMPowerStateVersion1);
1256*c54f35caSApple OSS Distributions 
1257*c54f35caSApple OSS Distributions 		fPowerStates            = powerStates;
1258*c54f35caSApple OSS Distributions 		fNumberOfPowerStates    = numberOfStates;
1259*c54f35caSApple OSS Distributions 		fControllingDriver      = powerDriver;
1260*c54f35caSApple OSS Distributions 		fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1261*c54f35caSApple OSS Distributions 
1262*c54f35caSApple OSS Distributions 		lowestPowerState   = fPowerStates[0].stateOrderToIndex;
1263*c54f35caSApple OSS Distributions 		fHighestPowerState = fPowerStates[numberOfStates - 1].stateOrderToIndex;
1264*c54f35caSApple OSS Distributions 
1265*c54f35caSApple OSS Distributions 		{
1266*c54f35caSApple OSS Distributions 			uint32_t        aotFlags;
1267*c54f35caSApple OSS Distributions 			IOService *     service;
1268*c54f35caSApple OSS Distributions 			OSObject *      object;
1269*c54f35caSApple OSS Distributions 			OSData *        data;
1270*c54f35caSApple OSS Distributions 
1271*c54f35caSApple OSS Distributions 			// Disallow kIOPMAOTPower states unless device tree enabled
1272*c54f35caSApple OSS Distributions 
1273*c54f35caSApple OSS Distributions 			aotFlags = 0;
1274*c54f35caSApple OSS Distributions 			service  = this;
1275*c54f35caSApple OSS Distributions 			while (service && !service->inPlane(gIODTPlane)) {
1276*c54f35caSApple OSS Distributions 				service = service->getProvider();
1277*c54f35caSApple OSS Distributions 			}
1278*c54f35caSApple OSS Distributions 			if (service) {
1279*c54f35caSApple OSS Distributions 				object = service->copyProperty(kIOPMAOTPowerKey, gIODTPlane);
1280*c54f35caSApple OSS Distributions 				data = OSDynamicCast(OSData, object);
1281*c54f35caSApple OSS Distributions 				if (data && (data->getLength() >= sizeof(uint32_t))) {
1282*c54f35caSApple OSS Distributions 					aotFlags = ((uint32_t *)data->getBytesNoCopy())[0];
1283*c54f35caSApple OSS Distributions 				}
1284*c54f35caSApple OSS Distributions 				OSSafeReleaseNULL(object);
1285*c54f35caSApple OSS Distributions 			}
1286*c54f35caSApple OSS Distributions 			if (!aotFlags) {
1287*c54f35caSApple OSS Distributions 				for (i = 0; i < numberOfStates; i++) {
1288*c54f35caSApple OSS Distributions 					if (kIOPMAOTPower & fPowerStates[i].inputPowerFlags) {
1289*c54f35caSApple OSS Distributions 						fPowerStates[i].inputPowerFlags  = 0xFFFFFFFF;
1290*c54f35caSApple OSS Distributions 						fPowerStates[i].capabilityFlags  = 0;
1291*c54f35caSApple OSS Distributions 						fPowerStates[i].outputPowerFlags = 0;
1292*c54f35caSApple OSS Distributions 					}
1293*c54f35caSApple OSS Distributions 				}
1294*c54f35caSApple OSS Distributions 			}
1295*c54f35caSApple OSS Distributions 		}
1296*c54f35caSApple OSS Distributions 
1297*c54f35caSApple OSS Distributions 		// OR'in all the output power flags
1298*c54f35caSApple OSS Distributions 		fMergedOutputPowerFlags = 0;
1299*c54f35caSApple OSS Distributions 		fDeviceUsablePowerState = lowestPowerState;
1300*c54f35caSApple OSS Distributions 		for (i = 0; i < numberOfStates; i++) {
1301*c54f35caSApple OSS Distributions 			fMergedOutputPowerFlags |= fPowerStates[i].outputPowerFlags;
1302*c54f35caSApple OSS Distributions 
1303*c54f35caSApple OSS Distributions 			stateIndex = fPowerStates[i].stateOrderToIndex;
1304*c54f35caSApple OSS Distributions 			assert(stateIndex < numberOfStates);
1305*c54f35caSApple OSS Distributions 			if ((fDeviceUsablePowerState == lowestPowerState) &&
1306*c54f35caSApple OSS Distributions 			    (fPowerStates[stateIndex].capabilityFlags & IOPMDeviceUsable)) {
1307*c54f35caSApple OSS Distributions 				// The minimum power state that the device is usable
1308*c54f35caSApple OSS Distributions 				fDeviceUsablePowerState = stateIndex;
1309*c54f35caSApple OSS Distributions 			}
1310*c54f35caSApple OSS Distributions 		}
1311*c54f35caSApple OSS Distributions 
1312*c54f35caSApple OSS Distributions 		// Register powerDriver as interested, unless already done.
1313*c54f35caSApple OSS Distributions 		// We don't want to register the default implementation since
1314*c54f35caSApple OSS Distributions 		// it does nothing. One ramification of not always registering
1315*c54f35caSApple OSS Distributions 		// is the one fewer retain count held.
1316*c54f35caSApple OSS Distributions 
1317*c54f35caSApple OSS Distributions 		root = getPlatform()->getProvider();
1318*c54f35caSApple OSS Distributions 		assert(root);
1319*c54f35caSApple OSS Distributions 		if (!root ||
1320*c54f35caSApple OSS Distributions 		    ((OSMemberFunctionCast(void (*)(void),
1321*c54f35caSApple OSS Distributions 		    root, &IOService::powerStateDidChangeTo)) !=
1322*c54f35caSApple OSS Distributions 		    ((OSMemberFunctionCast(void (*)(void),
1323*c54f35caSApple OSS Distributions 		    this, &IOService::powerStateDidChangeTo)))) ||
1324*c54f35caSApple OSS Distributions 		    ((OSMemberFunctionCast(void (*)(void),
1325*c54f35caSApple OSS Distributions 		    root, &IOService::powerStateWillChangeTo)) !=
1326*c54f35caSApple OSS Distributions 		    ((OSMemberFunctionCast(void (*)(void),
1327*c54f35caSApple OSS Distributions 		    this, &IOService::powerStateWillChangeTo))))) {
1328*c54f35caSApple OSS Distributions 			if (fInterestedDrivers->findItem(powerDriver) == NULL) {
1329*c54f35caSApple OSS Distributions 				PM_LOCK();
1330*c54f35caSApple OSS Distributions 				fInterestedDrivers->appendNewInformee(powerDriver);
1331*c54f35caSApple OSS Distributions 				PM_UNLOCK();
1332*c54f35caSApple OSS Distributions 			}
1333*c54f35caSApple OSS Distributions 		}
1334*c54f35caSApple OSS Distributions 
1335*c54f35caSApple OSS Distributions 		// Examine all existing power clients and perform limit check.
1336*c54f35caSApple OSS Distributions 
1337*c54f35caSApple OSS Distributions 		if (fPowerClients &&
1338*c54f35caSApple OSS Distributions 		    (iter = OSCollectionIterator::withCollection(fPowerClients))) {
1339*c54f35caSApple OSS Distributions 			const OSSymbol * client;
1340*c54f35caSApple OSS Distributions 			while ((client = (const OSSymbol *) iter->getNextObject())) {
1341*c54f35caSApple OSS Distributions 				IOPMPowerStateIndex powerState = getPowerStateForClient(client);
1342*c54f35caSApple OSS Distributions 				if (powerState >= numberOfStates) {
1343*c54f35caSApple OSS Distributions 					updatePowerClient(client, fHighestPowerState);
1344*c54f35caSApple OSS Distributions 				}
1345*c54f35caSApple OSS Distributions 			}
1346*c54f35caSApple OSS Distributions 			iter->release();
1347*c54f35caSApple OSS Distributions 		}
1348*c54f35caSApple OSS Distributions 
1349*c54f35caSApple OSS Distributions 		// Populate IOPMActions for a few special services
1350*c54f35caSApple OSS Distributions 		getPMRootDomain()->tagPowerPlaneService(this, &fPMActions, fNumberOfPowerStates - 1);
1351*c54f35caSApple OSS Distributions 
1352*c54f35caSApple OSS Distributions 		if (inPlane(gIOPowerPlane) && fParentsKnowState) {
1353*c54f35caSApple OSS Distributions 			IOPMPowerStateIndex tempDesire;
1354*c54f35caSApple OSS Distributions 			fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1355*c54f35caSApple OSS Distributions 			// initially change into the state we are already in
1356*c54f35caSApple OSS Distributions 			tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1357*c54f35caSApple OSS Distributions 			adjustPowerState(tempDesire);
1358*c54f35caSApple OSS Distributions 		}
1359*c54f35caSApple OSS Distributions 	} else {
1360*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
1361*c54f35caSApple OSS Distributions 		IODeleteData(powerStates, IOPMPSEntry, numberOfStates);
1362*c54f35caSApple OSS Distributions 	}
1363*c54f35caSApple OSS Distributions 
1364*c54f35caSApple OSS Distributions 	powerDriver->release();
1365*c54f35caSApple OSS Distributions }
1366*c54f35caSApple OSS Distributions 
1367*c54f35caSApple OSS Distributions //*********************************************************************************
1368*c54f35caSApple OSS Distributions // [public] registerInterestedDriver
1369*c54f35caSApple OSS Distributions //
1370*c54f35caSApple OSS Distributions // Add the caller to our list of interested drivers and return our current
1371*c54f35caSApple OSS Distributions // power state.  If we don't have a power-controlling driver yet, we will
1372*c54f35caSApple OSS Distributions // call this interested driver again later when we do get a driver and find
1373*c54f35caSApple OSS Distributions // out what the current power state of the device is.
1374*c54f35caSApple OSS Distributions //*********************************************************************************
1375*c54f35caSApple OSS Distributions 
1376*c54f35caSApple OSS Distributions IOPMPowerFlags
registerInterestedDriver(IOService * driver)1377*c54f35caSApple OSS Distributions IOService::registerInterestedDriver( IOService * driver )
1378*c54f35caSApple OSS Distributions {
1379*c54f35caSApple OSS Distributions 	IOPMRequest *   request;
1380*c54f35caSApple OSS Distributions 	bool            signal;
1381*c54f35caSApple OSS Distributions 
1382*c54f35caSApple OSS Distributions 	if (!driver || !initialized || !fInterestedDrivers) {
1383*c54f35caSApple OSS Distributions 		return 0;
1384*c54f35caSApple OSS Distributions 	}
1385*c54f35caSApple OSS Distributions 
1386*c54f35caSApple OSS Distributions 	PM_LOCK();
1387*c54f35caSApple OSS Distributions 	signal = (!fInsertInterestSet && !fRemoveInterestSet);
1388*c54f35caSApple OSS Distributions 	if (fInsertInterestSet == NULL) {
1389*c54f35caSApple OSS Distributions 		fInsertInterestSet = OSSet::withCapacity(4);
1390*c54f35caSApple OSS Distributions 	}
1391*c54f35caSApple OSS Distributions 	if (fInsertInterestSet) {
1392*c54f35caSApple OSS Distributions 		fInsertInterestSet->setObject(driver);
1393*c54f35caSApple OSS Distributions 		if (fRemoveInterestSet) {
1394*c54f35caSApple OSS Distributions 			fRemoveInterestSet->removeObject(driver);
1395*c54f35caSApple OSS Distributions 		}
1396*c54f35caSApple OSS Distributions 	}
1397*c54f35caSApple OSS Distributions 	PM_UNLOCK();
1398*c54f35caSApple OSS Distributions 
1399*c54f35caSApple OSS Distributions 	if (signal) {
1400*c54f35caSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1401*c54f35caSApple OSS Distributions 		if (request) {
1402*c54f35caSApple OSS Distributions 			submitPMRequest( request );
1403*c54f35caSApple OSS Distributions 		}
1404*c54f35caSApple OSS Distributions 	}
1405*c54f35caSApple OSS Distributions 
1406*c54f35caSApple OSS Distributions 	// This return value cannot be trusted, but return a value
1407*c54f35caSApple OSS Distributions 	// for those clients that care.
1408*c54f35caSApple OSS Distributions 
1409*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1410*c54f35caSApple OSS Distributions 	return kIOPMDeviceUsable;
1411*c54f35caSApple OSS Distributions }
1412*c54f35caSApple OSS Distributions 
1413*c54f35caSApple OSS Distributions //*********************************************************************************
1414*c54f35caSApple OSS Distributions // [public] deRegisterInterestedDriver
1415*c54f35caSApple OSS Distributions //*********************************************************************************
1416*c54f35caSApple OSS Distributions 
1417*c54f35caSApple OSS Distributions IOReturn
deRegisterInterestedDriver(IOService * driver)1418*c54f35caSApple OSS Distributions IOService::deRegisterInterestedDriver( IOService * driver )
1419*c54f35caSApple OSS Distributions {
1420*c54f35caSApple OSS Distributions 	IOPMinformee *      item;
1421*c54f35caSApple OSS Distributions 	IOPMRequest *       request;
1422*c54f35caSApple OSS Distributions 	bool                signal;
1423*c54f35caSApple OSS Distributions 
1424*c54f35caSApple OSS Distributions 	if (!driver) {
1425*c54f35caSApple OSS Distributions 		return kIOReturnBadArgument;
1426*c54f35caSApple OSS Distributions 	}
1427*c54f35caSApple OSS Distributions 	if (!initialized || !fInterestedDrivers) {
1428*c54f35caSApple OSS Distributions 		return IOPMNotPowerManaged;
1429*c54f35caSApple OSS Distributions 	}
1430*c54f35caSApple OSS Distributions 
1431*c54f35caSApple OSS Distributions 	PM_LOCK();
1432*c54f35caSApple OSS Distributions 	if (fInsertInterestSet) {
1433*c54f35caSApple OSS Distributions 		fInsertInterestSet->removeObject(driver);
1434*c54f35caSApple OSS Distributions 	}
1435*c54f35caSApple OSS Distributions 
1436*c54f35caSApple OSS Distributions 	item = fInterestedDrivers->findItem(driver);
1437*c54f35caSApple OSS Distributions 	if (!item) {
1438*c54f35caSApple OSS Distributions 		PM_UNLOCK();
1439*c54f35caSApple OSS Distributions 		return kIOReturnNotFound;
1440*c54f35caSApple OSS Distributions 	}
1441*c54f35caSApple OSS Distributions 
1442*c54f35caSApple OSS Distributions 	signal = (!fRemoveInterestSet && !fInsertInterestSet);
1443*c54f35caSApple OSS Distributions 	if (fRemoveInterestSet == NULL) {
1444*c54f35caSApple OSS Distributions 		fRemoveInterestSet = OSSet::withCapacity(4);
1445*c54f35caSApple OSS Distributions 	}
1446*c54f35caSApple OSS Distributions 	if (fRemoveInterestSet) {
1447*c54f35caSApple OSS Distributions 		fRemoveInterestSet->setObject(driver);
1448*c54f35caSApple OSS Distributions 		if (item->active) {
1449*c54f35caSApple OSS Distributions 			item->active = false;
1450*c54f35caSApple OSS Distributions 			waitForPMDriverCall( driver );
1451*c54f35caSApple OSS Distributions 		}
1452*c54f35caSApple OSS Distributions 	}
1453*c54f35caSApple OSS Distributions 	PM_UNLOCK();
1454*c54f35caSApple OSS Distributions 
1455*c54f35caSApple OSS Distributions 	if (signal) {
1456*c54f35caSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1457*c54f35caSApple OSS Distributions 		if (request) {
1458*c54f35caSApple OSS Distributions 			submitPMRequest( request );
1459*c54f35caSApple OSS Distributions 		}
1460*c54f35caSApple OSS Distributions 	}
1461*c54f35caSApple OSS Distributions 
1462*c54f35caSApple OSS Distributions 	return IOPMNoErr;
1463*c54f35caSApple OSS Distributions }
1464*c54f35caSApple OSS Distributions 
1465*c54f35caSApple OSS Distributions //*********************************************************************************
1466*c54f35caSApple OSS Distributions // [private] handleInterestChanged
1467*c54f35caSApple OSS Distributions //
1468*c54f35caSApple OSS Distributions // Handle interest added or removed.
1469*c54f35caSApple OSS Distributions //*********************************************************************************
1470*c54f35caSApple OSS Distributions 
1471*c54f35caSApple OSS Distributions void
handleInterestChanged(IOPMRequest * request)1472*c54f35caSApple OSS Distributions IOService::handleInterestChanged( IOPMRequest * request )
1473*c54f35caSApple OSS Distributions {
1474*c54f35caSApple OSS Distributions 	IOService *         driver;
1475*c54f35caSApple OSS Distributions 	IOPMinformee *      informee;
1476*c54f35caSApple OSS Distributions 	IOPMinformeeList *  list = fInterestedDrivers;
1477*c54f35caSApple OSS Distributions 
1478*c54f35caSApple OSS Distributions 	PM_LOCK();
1479*c54f35caSApple OSS Distributions 
1480*c54f35caSApple OSS Distributions 	if (fInsertInterestSet) {
1481*c54f35caSApple OSS Distributions 		while ((driver = (IOService *) fInsertInterestSet->getAnyObject())) {
1482*c54f35caSApple OSS Distributions 			if (list->findItem(driver) == NULL) {
1483*c54f35caSApple OSS Distributions 				list->appendNewInformee(driver);
1484*c54f35caSApple OSS Distributions 			}
1485*c54f35caSApple OSS Distributions 			fInsertInterestSet->removeObject(driver);
1486*c54f35caSApple OSS Distributions 		}
1487*c54f35caSApple OSS Distributions 		fInsertInterestSet->release();
1488*c54f35caSApple OSS Distributions 		fInsertInterestSet = NULL;
1489*c54f35caSApple OSS Distributions 	}
1490*c54f35caSApple OSS Distributions 
1491*c54f35caSApple OSS Distributions 	if (fRemoveInterestSet) {
1492*c54f35caSApple OSS Distributions 		while ((driver = (IOService *) fRemoveInterestSet->getAnyObject())) {
1493*c54f35caSApple OSS Distributions 			informee = list->findItem(driver);
1494*c54f35caSApple OSS Distributions 			if (informee) {
1495*c54f35caSApple OSS Distributions 				// Clean-up async interest acknowledgement
1496*c54f35caSApple OSS Distributions 				if (fHeadNotePendingAcks && informee->timer) {
1497*c54f35caSApple OSS Distributions 					informee->timer = 0;
1498*c54f35caSApple OSS Distributions 					fHeadNotePendingAcks--;
1499*c54f35caSApple OSS Distributions 				}
1500*c54f35caSApple OSS Distributions 				list->removeFromList(driver);
1501*c54f35caSApple OSS Distributions 			}
1502*c54f35caSApple OSS Distributions 			fRemoveInterestSet->removeObject(driver);
1503*c54f35caSApple OSS Distributions 		}
1504*c54f35caSApple OSS Distributions 		fRemoveInterestSet->release();
1505*c54f35caSApple OSS Distributions 		fRemoveInterestSet = NULL;
1506*c54f35caSApple OSS Distributions 	}
1507*c54f35caSApple OSS Distributions 
1508*c54f35caSApple OSS Distributions 	PM_UNLOCK();
1509*c54f35caSApple OSS Distributions }
1510*c54f35caSApple OSS Distributions 
1511*c54f35caSApple OSS Distributions //*********************************************************************************
1512*c54f35caSApple OSS Distributions // [public] acknowledgePowerChange
1513*c54f35caSApple OSS Distributions //
1514*c54f35caSApple OSS Distributions // After we notified one of the interested drivers or a power-domain child
1515*c54f35caSApple OSS Distributions // of an impending change in power, it has called to say it is now
1516*c54f35caSApple OSS Distributions // prepared for the change.  If this object is the last to
1517*c54f35caSApple OSS Distributions // acknowledge this change, we take whatever action we have been waiting
1518*c54f35caSApple OSS Distributions // for.
1519*c54f35caSApple OSS Distributions // That may include acknowledging to our parent.  In this case, we do it
1520*c54f35caSApple OSS Distributions // last of all to insure that this doesn't cause the parent to call us some-
1521*c54f35caSApple OSS Distributions // where else and alter data we are relying on here (like the very existance
1522*c54f35caSApple OSS Distributions // of a "current change note".)
1523*c54f35caSApple OSS Distributions //*********************************************************************************
1524*c54f35caSApple OSS Distributions 
1525*c54f35caSApple OSS Distributions IOReturn
acknowledgePowerChange(IOService * whichObject)1526*c54f35caSApple OSS Distributions IOService::acknowledgePowerChange( IOService * whichObject )
1527*c54f35caSApple OSS Distributions {
1528*c54f35caSApple OSS Distributions 	IOPMRequest * request;
1529*c54f35caSApple OSS Distributions 
1530*c54f35caSApple OSS Distributions 	if (!initialized) {
1531*c54f35caSApple OSS Distributions 		return IOPMNotYetInitialized;
1532*c54f35caSApple OSS Distributions 	}
1533*c54f35caSApple OSS Distributions 	if (!whichObject) {
1534*c54f35caSApple OSS Distributions 		return kIOReturnBadArgument;
1535*c54f35caSApple OSS Distributions 	}
1536*c54f35caSApple OSS Distributions 
1537*c54f35caSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1538*c54f35caSApple OSS Distributions 	if (!request) {
1539*c54f35caSApple OSS Distributions 		return kIOReturnNoMemory;
1540*c54f35caSApple OSS Distributions 	}
1541*c54f35caSApple OSS Distributions 
1542*c54f35caSApple OSS Distributions 	whichObject->retain();
1543*c54f35caSApple OSS Distributions 	request->fArg0 = whichObject;
1544*c54f35caSApple OSS Distributions 
1545*c54f35caSApple OSS Distributions 	submitPMRequest( request );
1546*c54f35caSApple OSS Distributions 	return IOPMNoErr;
1547*c54f35caSApple OSS Distributions }
1548*c54f35caSApple OSS Distributions 
1549*c54f35caSApple OSS Distributions //*********************************************************************************
1550*c54f35caSApple OSS Distributions // [private] handleAcknowledgePowerChange
1551*c54f35caSApple OSS Distributions //*********************************************************************************
1552*c54f35caSApple OSS Distributions 
1553*c54f35caSApple OSS Distributions bool
handleAcknowledgePowerChange(IOPMRequest * request)1554*c54f35caSApple OSS Distributions IOService::handleAcknowledgePowerChange( IOPMRequest * request )
1555*c54f35caSApple OSS Distributions {
1556*c54f35caSApple OSS Distributions 	IOPMinformee *      informee;
1557*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex childPower = kIOPMUnknown;
1558*c54f35caSApple OSS Distributions 	IOService *         theChild;
1559*c54f35caSApple OSS Distributions 	IOService *         whichObject;
1560*c54f35caSApple OSS Distributions 	bool                all_acked  = false;
1561*c54f35caSApple OSS Distributions 
1562*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1563*c54f35caSApple OSS Distributions 	whichObject = (IOService *) request->fArg0;
1564*c54f35caSApple OSS Distributions 	assert(whichObject);
1565*c54f35caSApple OSS Distributions 
1566*c54f35caSApple OSS Distributions 	// one of our interested drivers?
1567*c54f35caSApple OSS Distributions 	informee = fInterestedDrivers->findItem( whichObject );
1568*c54f35caSApple OSS Distributions 	if (informee == NULL) {
1569*c54f35caSApple OSS Distributions 		if (!isChild(whichObject, gIOPowerPlane)) {
1570*c54f35caSApple OSS Distributions 			OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1571*c54f35caSApple OSS Distributions 			goto no_err;
1572*c54f35caSApple OSS Distributions 		} else {
1573*c54f35caSApple OSS Distributions 			OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
1574*c54f35caSApple OSS Distributions 		}
1575*c54f35caSApple OSS Distributions 	} else {
1576*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
1577*c54f35caSApple OSS Distributions 	}
1578*c54f35caSApple OSS Distributions 
1579*c54f35caSApple OSS Distributions 	if (fHeadNotePendingAcks != 0) {
1580*c54f35caSApple OSS Distributions 		assert(fPowerStates != NULL);
1581*c54f35caSApple OSS Distributions 
1582*c54f35caSApple OSS Distributions 		// yes, make sure we're expecting acks
1583*c54f35caSApple OSS Distributions 		if (informee != NULL) {
1584*c54f35caSApple OSS Distributions 			// it's an interested driver
1585*c54f35caSApple OSS Distributions 			// make sure we're expecting this ack
1586*c54f35caSApple OSS Distributions 			if (informee->timer != 0) {
1587*c54f35caSApple OSS Distributions 				SOCD_TRACE_XNU(PM_INFORM_POWER_CHANGE_ACK,
1588*c54f35caSApple OSS Distributions 				    ADDR(informee->whatObject->getMetaClass()),
1589*c54f35caSApple OSS Distributions 				    ADDR(this->getMetaClass()),
1590*c54f35caSApple OSS Distributions 				    PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(informee->whatObject->getRegistryEntryID())),
1591*c54f35caSApple OSS Distributions 				    PACK_2X32(VALUE(0), VALUE(fDriverCallReason)));
1592*c54f35caSApple OSS Distributions 
1593*c54f35caSApple OSS Distributions 				if (informee->timer > 0) {
1594*c54f35caSApple OSS Distributions 					uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1595*c54f35caSApple OSS Distributions 					if (nsec > gIOPMSetPowerStateLogNS) {
1596*c54f35caSApple OSS Distributions 						getPMRootDomain()->pmStatsRecordApplicationResponse(
1597*c54f35caSApple OSS Distributions 							gIOPMStatsDriverPSChangeSlow, informee->whatObject->getName(),
1598*c54f35caSApple OSS Distributions 							fDriverCallReason, NS_TO_MS(nsec), informee->whatObject->getRegistryEntryID(),
1599*c54f35caSApple OSS Distributions 							NULL, fHeadNotePowerState, true);
1600*c54f35caSApple OSS Distributions 					}
1601*c54f35caSApple OSS Distributions 				}
1602*c54f35caSApple OSS Distributions 
1603*c54f35caSApple OSS Distributions 				// mark it acked
1604*c54f35caSApple OSS Distributions 				informee->timer = 0;
1605*c54f35caSApple OSS Distributions 				// that's one fewer to worry about
1606*c54f35caSApple OSS Distributions 				fHeadNotePendingAcks--;
1607*c54f35caSApple OSS Distributions 			} else {
1608*c54f35caSApple OSS Distributions 				// this driver has already acked
1609*c54f35caSApple OSS Distributions 				OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
1610*c54f35caSApple OSS Distributions 			}
1611*c54f35caSApple OSS Distributions 		} else {
1612*c54f35caSApple OSS Distributions 			// it's a child
1613*c54f35caSApple OSS Distributions 			// make sure we're expecting this ack
1614*c54f35caSApple OSS Distributions 			if (((IOPowerConnection *)whichObject)->getAwaitingAck()) {
1615*c54f35caSApple OSS Distributions 				// that's one fewer to worry about
1616*c54f35caSApple OSS Distributions 				fHeadNotePendingAcks--;
1617*c54f35caSApple OSS Distributions 				((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1618*c54f35caSApple OSS Distributions 				theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
1619*c54f35caSApple OSS Distributions 				if (theChild) {
1620*c54f35caSApple OSS Distributions 					childPower = theChild->currentPowerConsumption();
1621*c54f35caSApple OSS Distributions 					theChild->release();
1622*c54f35caSApple OSS Distributions 				}
1623*c54f35caSApple OSS Distributions 				if (childPower == kIOPMUnknown) {
1624*c54f35caSApple OSS Distributions 					fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
1625*c54f35caSApple OSS Distributions 				} else {
1626*c54f35caSApple OSS Distributions 					if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown) {
1627*c54f35caSApple OSS Distributions 						fHeadNotePowerArrayEntry->staticPower += childPower;
1628*c54f35caSApple OSS Distributions 					}
1629*c54f35caSApple OSS Distributions 				}
1630*c54f35caSApple OSS Distributions 			}
1631*c54f35caSApple OSS Distributions 		}
1632*c54f35caSApple OSS Distributions 
1633*c54f35caSApple OSS Distributions 		if (fHeadNotePendingAcks == 0) {
1634*c54f35caSApple OSS Distributions 			// yes, stop the timer
1635*c54f35caSApple OSS Distributions 			stop_ack_timer();
1636*c54f35caSApple OSS Distributions 			// and now we can continue
1637*c54f35caSApple OSS Distributions 			all_acked = true;
1638*c54f35caSApple OSS Distributions 			getPMRootDomain()->reset_watchdog_timer(this, 0);
1639*c54f35caSApple OSS Distributions 		}
1640*c54f35caSApple OSS Distributions 	} else {
1641*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1642*c54f35caSApple OSS Distributions 	}
1643*c54f35caSApple OSS Distributions 
1644*c54f35caSApple OSS Distributions no_err:
1645*c54f35caSApple OSS Distributions 	if (whichObject) {
1646*c54f35caSApple OSS Distributions 		whichObject->release();
1647*c54f35caSApple OSS Distributions 	}
1648*c54f35caSApple OSS Distributions 
1649*c54f35caSApple OSS Distributions 	return all_acked;
1650*c54f35caSApple OSS Distributions }
1651*c54f35caSApple OSS Distributions 
1652*c54f35caSApple OSS Distributions //*********************************************************************************
1653*c54f35caSApple OSS Distributions // [public] acknowledgeSetPowerState
1654*c54f35caSApple OSS Distributions //
1655*c54f35caSApple OSS Distributions // After we instructed our controlling driver to change power states,
1656*c54f35caSApple OSS Distributions // it has called to say it has finished doing so.
1657*c54f35caSApple OSS Distributions // We continue to process the power state change.
1658*c54f35caSApple OSS Distributions //*********************************************************************************
1659*c54f35caSApple OSS Distributions 
1660*c54f35caSApple OSS Distributions IOReturn
acknowledgeSetPowerState(void)1661*c54f35caSApple OSS Distributions IOService::acknowledgeSetPowerState( void )
1662*c54f35caSApple OSS Distributions {
1663*c54f35caSApple OSS Distributions 	IOPMRequest * request;
1664*c54f35caSApple OSS Distributions 
1665*c54f35caSApple OSS Distributions 	if (!initialized) {
1666*c54f35caSApple OSS Distributions 		return IOPMNotYetInitialized;
1667*c54f35caSApple OSS Distributions 	}
1668*c54f35caSApple OSS Distributions 
1669*c54f35caSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1670*c54f35caSApple OSS Distributions 	if (!request) {
1671*c54f35caSApple OSS Distributions 		return kIOReturnNoMemory;
1672*c54f35caSApple OSS Distributions 	}
1673*c54f35caSApple OSS Distributions 
1674*c54f35caSApple OSS Distributions 	submitPMRequest( request );
1675*c54f35caSApple OSS Distributions 	return kIOReturnSuccess;
1676*c54f35caSApple OSS Distributions }
1677*c54f35caSApple OSS Distributions 
1678*c54f35caSApple OSS Distributions //*********************************************************************************
1679*c54f35caSApple OSS Distributions // [private] handleAcknowledgeSetPowerState
1680*c54f35caSApple OSS Distributions //*********************************************************************************
1681*c54f35caSApple OSS Distributions 
1682*c54f35caSApple OSS Distributions bool
handleAcknowledgeSetPowerState(IOPMRequest * request __unused)1683*c54f35caSApple OSS Distributions IOService::handleAcknowledgeSetPowerState( IOPMRequest * request __unused)
1684*c54f35caSApple OSS Distributions {
1685*c54f35caSApple OSS Distributions 	const OSMetaClass  *controllingDriverMetaClass = NULL;
1686*c54f35caSApple OSS Distributions 	uint32_t            controllingDriverRegistryEntryID = 0;
1687*c54f35caSApple OSS Distributions 	bool                more = false;
1688*c54f35caSApple OSS Distributions 	bool                trace_this_ack = true;
1689*c54f35caSApple OSS Distributions 
1690*c54f35caSApple OSS Distributions 	if (fDriverTimer == -1) {
1691*c54f35caSApple OSS Distributions 		// driver acked while setPowerState() call is in-flight.
1692*c54f35caSApple OSS Distributions 		// take this ack, return value from setPowerState() is irrelevant.
1693*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogDriverAcknowledgeSet,
1694*c54f35caSApple OSS Distributions 		    (uintptr_t) this, fDriverTimer);
1695*c54f35caSApple OSS Distributions 		fDriverTimer = 0;
1696*c54f35caSApple OSS Distributions 	} else if (fDriverTimer > 0) {
1697*c54f35caSApple OSS Distributions 		// expected ack, stop the timer
1698*c54f35caSApple OSS Distributions 		stop_ack_timer();
1699*c54f35caSApple OSS Distributions 
1700*c54f35caSApple OSS Distributions 		getPMRootDomain()->reset_watchdog_timer(this, 0);
1701*c54f35caSApple OSS Distributions 
1702*c54f35caSApple OSS Distributions 		uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
1703*c54f35caSApple OSS Distributions 		if (nsec > gIOPMSetPowerStateLogNS) {
1704*c54f35caSApple OSS Distributions 			getPMRootDomain()->pmStatsRecordApplicationResponse(
1705*c54f35caSApple OSS Distributions 				gIOPMStatsDriverPSChangeSlow,
1706*c54f35caSApple OSS Distributions 				fName, kDriverCallSetPowerState, NS_TO_MS(nsec), getRegistryEntryID(),
1707*c54f35caSApple OSS Distributions 				NULL, fHeadNotePowerState, true);
1708*c54f35caSApple OSS Distributions 		}
1709*c54f35caSApple OSS Distributions 
1710*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogDriverAcknowledgeSet, (uintptr_t) this, fDriverTimer);
1711*c54f35caSApple OSS Distributions 		fDriverTimer = 0;
1712*c54f35caSApple OSS Distributions 		more = true;
1713*c54f35caSApple OSS Distributions 	} else {
1714*c54f35caSApple OSS Distributions 		// unexpected ack
1715*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogAcknowledgeErr4, (uintptr_t) this, 0);
1716*c54f35caSApple OSS Distributions 		trace_this_ack = false;
1717*c54f35caSApple OSS Distributions 	}
1718*c54f35caSApple OSS Distributions 
1719*c54f35caSApple OSS Distributions 	if (trace_this_ack) {
1720*c54f35caSApple OSS Distributions 		if (fControllingDriver) {
1721*c54f35caSApple OSS Distributions 			controllingDriverMetaClass = fControllingDriver->getMetaClass();
1722*c54f35caSApple OSS Distributions 			controllingDriverRegistryEntryID = (uint32_t)fControllingDriver->getRegistryEntryID();
1723*c54f35caSApple OSS Distributions 		}
1724*c54f35caSApple OSS Distributions 
1725*c54f35caSApple OSS Distributions 		SOCD_TRACE_XNU(PM_SET_POWER_STATE_ACK,
1726*c54f35caSApple OSS Distributions 		    ADDR(controllingDriverMetaClass),
1727*c54f35caSApple OSS Distributions 		    ADDR(this->getMetaClass()),
1728*c54f35caSApple OSS Distributions 		    PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
1729*c54f35caSApple OSS Distributions 		    PACK_2X32(VALUE(fHeadNotePowerState), VALUE(0)));
1730*c54f35caSApple OSS Distributions 	}
1731*c54f35caSApple OSS Distributions 
1732*c54f35caSApple OSS Distributions 	return more;
1733*c54f35caSApple OSS Distributions }
1734*c54f35caSApple OSS Distributions 
1735*c54f35caSApple OSS Distributions //*********************************************************************************
1736*c54f35caSApple OSS Distributions // [private] adjustPowerState
1737*c54f35caSApple OSS Distributions //*********************************************************************************
1738*c54f35caSApple OSS Distributions 
1739*c54f35caSApple OSS Distributions void
adjustPowerState(IOPMPowerStateIndex clamp)1740*c54f35caSApple OSS Distributions IOService::adjustPowerState( IOPMPowerStateIndex clamp )
1741*c54f35caSApple OSS Distributions {
1742*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1743*c54f35caSApple OSS Distributions 	computeDesiredState(clamp, false);
1744*c54f35caSApple OSS Distributions 	if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane)) {
1745*c54f35caSApple OSS Distributions 		IOPMPowerChangeFlags changeFlags = kIOPMSelfInitiated;
1746*c54f35caSApple OSS Distributions 
1747*c54f35caSApple OSS Distributions 		// Indicate that children desires must be ignored, and do not ask
1748*c54f35caSApple OSS Distributions 		// apps for permission to drop power. This is used by root domain
1749*c54f35caSApple OSS Distributions 		// for demand sleep.
1750*c54f35caSApple OSS Distributions 
1751*c54f35caSApple OSS Distributions 		if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride) {
1752*c54f35caSApple OSS Distributions 			changeFlags |= (kIOPMIgnoreChildren | kIOPMSkipAskPowerDown);
1753*c54f35caSApple OSS Distributions 		}
1754*c54f35caSApple OSS Distributions 
1755*c54f35caSApple OSS Distributions 		startPowerChange(
1756*c54f35caSApple OSS Distributions 			/* flags        */ changeFlags,
1757*c54f35caSApple OSS Distributions 			/* power state  */ fDesiredPowerState,
1758*c54f35caSApple OSS Distributions 			/* domain flags */ 0,
1759*c54f35caSApple OSS Distributions 			/* connection   */ NULL,
1760*c54f35caSApple OSS Distributions 			/* parent flags */ 0);
1761*c54f35caSApple OSS Distributions 	}
1762*c54f35caSApple OSS Distributions }
1763*c54f35caSApple OSS Distributions 
1764*c54f35caSApple OSS Distributions //*********************************************************************************
1765*c54f35caSApple OSS Distributions // [public] synchronizePowerTree
1766*c54f35caSApple OSS Distributions //*********************************************************************************
1767*c54f35caSApple OSS Distributions 
1768*c54f35caSApple OSS Distributions IOReturn
synchronizePowerTree(IOOptionBits options,IOService * notifyRoot)1769*c54f35caSApple OSS Distributions IOService::synchronizePowerTree(
1770*c54f35caSApple OSS Distributions 	IOOptionBits    options,
1771*c54f35caSApple OSS Distributions 	IOService *     notifyRoot )
1772*c54f35caSApple OSS Distributions {
1773*c54f35caSApple OSS Distributions 	IOPMRequest *   request_c = NULL;
1774*c54f35caSApple OSS Distributions 	IOPMRequest *   request_s;
1775*c54f35caSApple OSS Distributions 
1776*c54f35caSApple OSS Distributions 	if (this != getPMRootDomain()) {
1777*c54f35caSApple OSS Distributions 		return kIOReturnBadArgument;
1778*c54f35caSApple OSS Distributions 	}
1779*c54f35caSApple OSS Distributions 	if (!initialized) {
1780*c54f35caSApple OSS Distributions 		return kIOPMNotYetInitialized;
1781*c54f35caSApple OSS Distributions 	}
1782*c54f35caSApple OSS Distributions 
1783*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogCSynchronizePowerTree, options, (notifyRoot != NULL));
1784*c54f35caSApple OSS Distributions 
1785*c54f35caSApple OSS Distributions 	if (notifyRoot) {
1786*c54f35caSApple OSS Distributions 		IOPMRequest * nr;
1787*c54f35caSApple OSS Distributions 
1788*c54f35caSApple OSS Distributions 		// Cancels don't need to be synchronized.
1789*c54f35caSApple OSS Distributions 		nr = acquirePMRequest(notifyRoot, kIOPMRequestTypeChildNotifyDelayCancel);
1790*c54f35caSApple OSS Distributions 		if (nr) {
1791*c54f35caSApple OSS Distributions 			submitPMRequest(nr);
1792*c54f35caSApple OSS Distributions 		}
1793*c54f35caSApple OSS Distributions 
1794*c54f35caSApple OSS Distributions 		// For display wrangler or any other delay-eligible (dark wake clamped)
1795*c54f35caSApple OSS Distributions 		// drivers attached to root domain in the power plane.
1796*c54f35caSApple OSS Distributions 		nr = acquirePMRequest(getPMRootDomain(), kIOPMRequestTypeChildNotifyDelayCancel);
1797*c54f35caSApple OSS Distributions 		if (nr) {
1798*c54f35caSApple OSS Distributions 			submitPMRequest(nr);
1799*c54f35caSApple OSS Distributions 		}
1800*c54f35caSApple OSS Distributions 	}
1801*c54f35caSApple OSS Distributions 
1802*c54f35caSApple OSS Distributions 	request_s = acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree );
1803*c54f35caSApple OSS Distributions 	if (!request_s) {
1804*c54f35caSApple OSS Distributions 		goto error_no_memory;
1805*c54f35caSApple OSS Distributions 	}
1806*c54f35caSApple OSS Distributions 
1807*c54f35caSApple OSS Distributions 	if (options & kIOPMSyncCancelPowerDown) {
1808*c54f35caSApple OSS Distributions 		request_c = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
1809*c54f35caSApple OSS Distributions 	}
1810*c54f35caSApple OSS Distributions 	if (request_c) {
1811*c54f35caSApple OSS Distributions 		request_c->attachNextRequest( request_s );
1812*c54f35caSApple OSS Distributions 		submitPMRequest(request_c);
1813*c54f35caSApple OSS Distributions 	}
1814*c54f35caSApple OSS Distributions 
1815*c54f35caSApple OSS Distributions 	request_s->fArg0 = (void *)(uintptr_t) options;
1816*c54f35caSApple OSS Distributions 	submitPMRequest(request_s);
1817*c54f35caSApple OSS Distributions 
1818*c54f35caSApple OSS Distributions 	return kIOReturnSuccess;
1819*c54f35caSApple OSS Distributions 
1820*c54f35caSApple OSS Distributions error_no_memory:
1821*c54f35caSApple OSS Distributions 	if (request_c) {
1822*c54f35caSApple OSS Distributions 		releasePMRequest(request_c);
1823*c54f35caSApple OSS Distributions 	}
1824*c54f35caSApple OSS Distributions 	if (request_s) {
1825*c54f35caSApple OSS Distributions 		releasePMRequest(request_s);
1826*c54f35caSApple OSS Distributions 	}
1827*c54f35caSApple OSS Distributions 	return kIOReturnNoMemory;
1828*c54f35caSApple OSS Distributions }
1829*c54f35caSApple OSS Distributions 
1830*c54f35caSApple OSS Distributions //*********************************************************************************
1831*c54f35caSApple OSS Distributions // [private] handleSynchronizePowerTree
1832*c54f35caSApple OSS Distributions //*********************************************************************************
1833*c54f35caSApple OSS Distributions 
1834*c54f35caSApple OSS Distributions void
handleSynchronizePowerTree(IOPMRequest * request)1835*c54f35caSApple OSS Distributions IOService::handleSynchronizePowerTree( IOPMRequest * request )
1836*c54f35caSApple OSS Distributions {
1837*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1838*c54f35caSApple OSS Distributions 	if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane) &&
1839*c54f35caSApple OSS Distributions 	    (fCurrentPowerState == fHighestPowerState)) {
1840*c54f35caSApple OSS Distributions 		IOPMPowerChangeFlags options = (IOPMPowerChangeFlags)(uintptr_t) request->fArg0;
1841*c54f35caSApple OSS Distributions 
1842*c54f35caSApple OSS Distributions 		startPowerChange(
1843*c54f35caSApple OSS Distributions 			/* flags        */ kIOPMSelfInitiated | kIOPMSynchronize |
1844*c54f35caSApple OSS Distributions 			(options & kIOPMSyncNoChildNotify),
1845*c54f35caSApple OSS Distributions 			/* power state  */ fCurrentPowerState,
1846*c54f35caSApple OSS Distributions 			/* domain flags */ 0,
1847*c54f35caSApple OSS Distributions 			/* connection   */ NULL,
1848*c54f35caSApple OSS Distributions 			/* parent flags */ 0);
1849*c54f35caSApple OSS Distributions 	}
1850*c54f35caSApple OSS Distributions }
1851*c54f35caSApple OSS Distributions 
1852*c54f35caSApple OSS Distributions #ifndef __LP64__
1853*c54f35caSApple OSS Distributions //*********************************************************************************
1854*c54f35caSApple OSS Distributions // [deprecated] powerDomainWillChangeTo
1855*c54f35caSApple OSS Distributions //
1856*c54f35caSApple OSS Distributions // Called by the power-hierarchy parent notifying of a new power state
1857*c54f35caSApple OSS Distributions // in the power domain.
1858*c54f35caSApple OSS Distributions // We enqueue a parent power-change to our queue of power changes.
1859*c54f35caSApple OSS Distributions // This may or may not cause us to change power, depending on what
1860*c54f35caSApple OSS Distributions // kind of change is occuring in the domain.
1861*c54f35caSApple OSS Distributions //*********************************************************************************
1862*c54f35caSApple OSS Distributions 
1863*c54f35caSApple OSS Distributions IOReturn
powerDomainWillChangeTo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent)1864*c54f35caSApple OSS Distributions IOService::powerDomainWillChangeTo(
1865*c54f35caSApple OSS Distributions 	IOPMPowerFlags      newPowerFlags,
1866*c54f35caSApple OSS Distributions 	IOPowerConnection * whichParent )
1867*c54f35caSApple OSS Distributions {
1868*c54f35caSApple OSS Distributions 	assert(false);
1869*c54f35caSApple OSS Distributions 	return kIOReturnUnsupported;
1870*c54f35caSApple OSS Distributions }
1871*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
1872*c54f35caSApple OSS Distributions 
1873*c54f35caSApple OSS Distributions //*********************************************************************************
1874*c54f35caSApple OSS Distributions // [private] handlePowerDomainWillChangeTo
1875*c54f35caSApple OSS Distributions //*********************************************************************************
1876*c54f35caSApple OSS Distributions 
1877*c54f35caSApple OSS Distributions void
handlePowerDomainWillChangeTo(IOPMRequest * request)1878*c54f35caSApple OSS Distributions IOService::handlePowerDomainWillChangeTo( IOPMRequest * request )
1879*c54f35caSApple OSS Distributions {
1880*c54f35caSApple OSS Distributions 	IOPMPowerFlags       parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1881*c54f35caSApple OSS Distributions 	IOPowerConnection *  whichParent = (IOPowerConnection *) request->fArg1;
1882*c54f35caSApple OSS Distributions 	IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1883*c54f35caSApple OSS Distributions 	IOPMPowerChangeFlags myChangeFlags;
1884*c54f35caSApple OSS Distributions 	OSIterator *         iter;
1885*c54f35caSApple OSS Distributions 	OSObject *           next;
1886*c54f35caSApple OSS Distributions 	IOPowerConnection *  connection;
1887*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex  maxPowerState;
1888*c54f35caSApple OSS Distributions 	IOPMPowerFlags       combinedPowerFlags;
1889*c54f35caSApple OSS Distributions 	IOReturn             result = IOPMAckImplied;
1890*c54f35caSApple OSS Distributions 
1891*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
1892*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogWillChange, parentPowerFlags, 0);
1893*c54f35caSApple OSS Distributions 
1894*c54f35caSApple OSS Distributions 	if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck()) {
1895*c54f35caSApple OSS Distributions 		PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1896*c54f35caSApple OSS Distributions 		goto exit_no_ack;
1897*c54f35caSApple OSS Distributions 	}
1898*c54f35caSApple OSS Distributions 
1899*c54f35caSApple OSS Distributions 	// Combine parents' output power flags.
1900*c54f35caSApple OSS Distributions 
1901*c54f35caSApple OSS Distributions 	combinedPowerFlags = 0;
1902*c54f35caSApple OSS Distributions 
1903*c54f35caSApple OSS Distributions 	iter = getParentIterator(gIOPowerPlane);
1904*c54f35caSApple OSS Distributions 	if (iter) {
1905*c54f35caSApple OSS Distributions 		while ((next = iter->getNextObject())) {
1906*c54f35caSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, next))) {
1907*c54f35caSApple OSS Distributions 				if (connection == whichParent) {
1908*c54f35caSApple OSS Distributions 					combinedPowerFlags |= parentPowerFlags;
1909*c54f35caSApple OSS Distributions 				} else {
1910*c54f35caSApple OSS Distributions 					combinedPowerFlags |= connection->parentCurrentPowerFlags();
1911*c54f35caSApple OSS Distributions 				}
1912*c54f35caSApple OSS Distributions 			}
1913*c54f35caSApple OSS Distributions 		}
1914*c54f35caSApple OSS Distributions 		iter->release();
1915*c54f35caSApple OSS Distributions 	}
1916*c54f35caSApple OSS Distributions 
1917*c54f35caSApple OSS Distributions 	// If our initial change has yet to occur, then defer the power change
1918*c54f35caSApple OSS Distributions 	// until after the power domain has completed its power transition.
1919*c54f35caSApple OSS Distributions 
1920*c54f35caSApple OSS Distributions 	if (fControllingDriver && !fInitialPowerChange) {
1921*c54f35caSApple OSS Distributions 		maxPowerState = fControllingDriver->maxCapabilityForDomainState(
1922*c54f35caSApple OSS Distributions 			combinedPowerFlags);
1923*c54f35caSApple OSS Distributions 
1924*c54f35caSApple OSS Distributions 		if (parentChangeFlags & kIOPMDomainPowerDrop) {
1925*c54f35caSApple OSS Distributions 			// fMaxPowerState set a limit on self-initiated power changes.
1926*c54f35caSApple OSS Distributions 			// Update it before a parent power drop.
1927*c54f35caSApple OSS Distributions 			fMaxPowerState = maxPowerState;
1928*c54f35caSApple OSS Distributions 		}
1929*c54f35caSApple OSS Distributions 
1930*c54f35caSApple OSS Distributions 		// Use kIOPMSynchronize below instead of kIOPMRootBroadcastFlags
1931*c54f35caSApple OSS Distributions 		// to avoid propagating the root change flags if any service must
1932*c54f35caSApple OSS Distributions 		// change power state due to root's will-change notification.
1933*c54f35caSApple OSS Distributions 		// Root does not change power state for kIOPMSynchronize.
1934*c54f35caSApple OSS Distributions 
1935*c54f35caSApple OSS Distributions 		myChangeFlags = kIOPMParentInitiated | kIOPMDomainWillChange |
1936*c54f35caSApple OSS Distributions 		    (parentChangeFlags & kIOPMSynchronize);
1937*c54f35caSApple OSS Distributions 
1938*c54f35caSApple OSS Distributions 		result = startPowerChange(
1939*c54f35caSApple OSS Distributions 			/* flags        */ myChangeFlags,
1940*c54f35caSApple OSS Distributions 			/* power state  */ maxPowerState,
1941*c54f35caSApple OSS Distributions 			/* domain flags */ combinedPowerFlags,
1942*c54f35caSApple OSS Distributions 			/* connection   */ whichParent,
1943*c54f35caSApple OSS Distributions 			/* parent flags */ parentPowerFlags);
1944*c54f35caSApple OSS Distributions 	}
1945*c54f35caSApple OSS Distributions 
1946*c54f35caSApple OSS Distributions 	// If parent is dropping power, immediately update the parent's
1947*c54f35caSApple OSS Distributions 	// capability flags. Any future merging of parent(s) combined
1948*c54f35caSApple OSS Distributions 	// power flags should account for this power drop.
1949*c54f35caSApple OSS Distributions 
1950*c54f35caSApple OSS Distributions 	if (parentChangeFlags & kIOPMDomainPowerDrop) {
1951*c54f35caSApple OSS Distributions 		setParentInfo(parentPowerFlags, whichParent, true);
1952*c54f35caSApple OSS Distributions 	}
1953*c54f35caSApple OSS Distributions 
1954*c54f35caSApple OSS Distributions 	// Parent is expecting an ACK from us. If we did not embark on a state
1955*c54f35caSApple OSS Distributions 	// transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1956*c54f35caSApple OSS Distributions 	// still required to issue an ACK to our parent.
1957*c54f35caSApple OSS Distributions 
1958*c54f35caSApple OSS Distributions 	if (IOPMAckImplied == result) {
1959*c54f35caSApple OSS Distributions 		IOService * parent;
1960*c54f35caSApple OSS Distributions 		parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1961*c54f35caSApple OSS Distributions 		assert(parent);
1962*c54f35caSApple OSS Distributions 		if (parent) {
1963*c54f35caSApple OSS Distributions 			parent->acknowledgePowerChange( whichParent );
1964*c54f35caSApple OSS Distributions 			parent->release();
1965*c54f35caSApple OSS Distributions 		}
1966*c54f35caSApple OSS Distributions 	}
1967*c54f35caSApple OSS Distributions 
1968*c54f35caSApple OSS Distributions exit_no_ack:
1969*c54f35caSApple OSS Distributions 	// Drop the retain from notifyChild().
1970*c54f35caSApple OSS Distributions 	if (whichParent) {
1971*c54f35caSApple OSS Distributions 		whichParent->release();
1972*c54f35caSApple OSS Distributions 	}
1973*c54f35caSApple OSS Distributions }
1974*c54f35caSApple OSS Distributions 
1975*c54f35caSApple OSS Distributions #ifndef __LP64__
1976*c54f35caSApple OSS Distributions //*********************************************************************************
1977*c54f35caSApple OSS Distributions // [deprecated] powerDomainDidChangeTo
1978*c54f35caSApple OSS Distributions //
1979*c54f35caSApple OSS Distributions // Called by the power-hierarchy parent after the power state of the power domain
1980*c54f35caSApple OSS Distributions // has settled at a new level.
1981*c54f35caSApple OSS Distributions // We enqueue a parent power-change to our queue of power changes.
1982*c54f35caSApple OSS Distributions // This may or may not cause us to change power, depending on what
1983*c54f35caSApple OSS Distributions // kind of change is occuring in the domain.
1984*c54f35caSApple OSS Distributions //*********************************************************************************
1985*c54f35caSApple OSS Distributions 
1986*c54f35caSApple OSS Distributions IOReturn
powerDomainDidChangeTo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent)1987*c54f35caSApple OSS Distributions IOService::powerDomainDidChangeTo(
1988*c54f35caSApple OSS Distributions 	IOPMPowerFlags      newPowerFlags,
1989*c54f35caSApple OSS Distributions 	IOPowerConnection * whichParent )
1990*c54f35caSApple OSS Distributions {
1991*c54f35caSApple OSS Distributions 	assert(false);
1992*c54f35caSApple OSS Distributions 	return kIOReturnUnsupported;
1993*c54f35caSApple OSS Distributions }
1994*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
1995*c54f35caSApple OSS Distributions 
1996*c54f35caSApple OSS Distributions //*********************************************************************************
1997*c54f35caSApple OSS Distributions // [private] handlePowerDomainDidChangeTo
1998*c54f35caSApple OSS Distributions //*********************************************************************************
1999*c54f35caSApple OSS Distributions 
2000*c54f35caSApple OSS Distributions void
handlePowerDomainDidChangeTo(IOPMRequest * request)2001*c54f35caSApple OSS Distributions IOService::handlePowerDomainDidChangeTo( IOPMRequest * request )
2002*c54f35caSApple OSS Distributions {
2003*c54f35caSApple OSS Distributions 	IOPMPowerFlags       parentPowerFlags = (IOPMPowerFlags) request->fArg0;
2004*c54f35caSApple OSS Distributions 	IOPowerConnection *  whichParent = (IOPowerConnection *) request->fArg1;
2005*c54f35caSApple OSS Distributions 	IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
2006*c54f35caSApple OSS Distributions 	IOPMPowerChangeFlags myChangeFlags;
2007*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex  maxPowerState;
2008*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex  initialDesire = kPowerStateZero;
2009*c54f35caSApple OSS Distributions 	bool                 computeDesire = false;
2010*c54f35caSApple OSS Distributions 	bool                 desireChanged = false;
2011*c54f35caSApple OSS Distributions 	bool                 savedParentsKnowState;
2012*c54f35caSApple OSS Distributions 	IOReturn             result = IOPMAckImplied;
2013*c54f35caSApple OSS Distributions 
2014*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
2015*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogDidChange, parentPowerFlags, 0);
2016*c54f35caSApple OSS Distributions 
2017*c54f35caSApple OSS Distributions 	if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck()) {
2018*c54f35caSApple OSS Distributions 		PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
2019*c54f35caSApple OSS Distributions 		goto exit_no_ack;
2020*c54f35caSApple OSS Distributions 	}
2021*c54f35caSApple OSS Distributions 
2022*c54f35caSApple OSS Distributions 	savedParentsKnowState = fParentsKnowState;
2023*c54f35caSApple OSS Distributions 
2024*c54f35caSApple OSS Distributions 	setParentInfo(parentPowerFlags, whichParent, true);
2025*c54f35caSApple OSS Distributions 
2026*c54f35caSApple OSS Distributions 	if (fControllingDriver) {
2027*c54f35caSApple OSS Distributions 		maxPowerState = fControllingDriver->maxCapabilityForDomainState(
2028*c54f35caSApple OSS Distributions 			fParentsCurrentPowerFlags);
2029*c54f35caSApple OSS Distributions 
2030*c54f35caSApple OSS Distributions 		if ((parentChangeFlags & kIOPMDomainPowerDrop) == 0) {
2031*c54f35caSApple OSS Distributions 			// fMaxPowerState set a limit on self-initiated power changes.
2032*c54f35caSApple OSS Distributions 			// Update it after a parent power rise.
2033*c54f35caSApple OSS Distributions 			fMaxPowerState = maxPowerState;
2034*c54f35caSApple OSS Distributions 		}
2035*c54f35caSApple OSS Distributions 
2036*c54f35caSApple OSS Distributions 		if (fInitialPowerChange) {
2037*c54f35caSApple OSS Distributions 			computeDesire = true;
2038*c54f35caSApple OSS Distributions 			initialDesire = fControllingDriver->initialPowerStateForDomainState(
2039*c54f35caSApple OSS Distributions 				fParentsCurrentPowerFlags);
2040*c54f35caSApple OSS Distributions 		} else if (parentChangeFlags & kIOPMRootChangeUp) {
2041*c54f35caSApple OSS Distributions 			if (fAdvisoryTickleUsed) {
2042*c54f35caSApple OSS Distributions 				// On system wake, re-compute the desired power state since
2043*c54f35caSApple OSS Distributions 				// gIOPMAdvisoryTickleEnabled will change for a full wake,
2044*c54f35caSApple OSS Distributions 				// which is an input to computeDesiredState(). This is not
2045*c54f35caSApple OSS Distributions 				// necessary for a dark wake because powerChangeDone() will
2046*c54f35caSApple OSS Distributions 				// handle the dark to full wake case, but it does no harm.
2047*c54f35caSApple OSS Distributions 
2048*c54f35caSApple OSS Distributions 				desireChanged = true;
2049*c54f35caSApple OSS Distributions 			}
2050*c54f35caSApple OSS Distributions 
2051*c54f35caSApple OSS Distributions 			if (fResetPowerStateOnWake) {
2052*c54f35caSApple OSS Distributions 				// Query the driver for the desired power state on system wake.
2053*c54f35caSApple OSS Distributions 				// Default implementation returns the lowest power state.
2054*c54f35caSApple OSS Distributions 
2055*c54f35caSApple OSS Distributions 				IOPMPowerStateIndex wakePowerState =
2056*c54f35caSApple OSS Distributions 				    fControllingDriver->initialPowerStateForDomainState(
2057*c54f35caSApple OSS Distributions 					kIOPMRootDomainState | kIOPMPowerOn );
2058*c54f35caSApple OSS Distributions 
2059*c54f35caSApple OSS Distributions 				// fDesiredPowerState was adjusted before going to sleep
2060*c54f35caSApple OSS Distributions 				// with fDeviceDesire at min.
2061*c54f35caSApple OSS Distributions 
2062*c54f35caSApple OSS Distributions 				if (StateOrder(wakePowerState) > StateOrder(fDesiredPowerState)) {
2063*c54f35caSApple OSS Distributions 					// Must schedule a power adjustment if we changed the
2064*c54f35caSApple OSS Distributions 					// device desire. That will update the desired domain
2065*c54f35caSApple OSS Distributions 					// power on the parent power connection and ping the
2066*c54f35caSApple OSS Distributions 					// power parent if necessary.
2067*c54f35caSApple OSS Distributions 
2068*c54f35caSApple OSS Distributions 					updatePowerClient(gIOPMPowerClientDevice, wakePowerState);
2069*c54f35caSApple OSS Distributions 					desireChanged = true;
2070*c54f35caSApple OSS Distributions 				}
2071*c54f35caSApple OSS Distributions 			}
2072*c54f35caSApple OSS Distributions 		}
2073*c54f35caSApple OSS Distributions 
2074*c54f35caSApple OSS Distributions 		if (computeDesire || desireChanged) {
2075*c54f35caSApple OSS Distributions 			computeDesiredState(initialDesire, false);
2076*c54f35caSApple OSS Distributions 		}
2077*c54f35caSApple OSS Distributions 
2078*c54f35caSApple OSS Distributions 		// Absorb and propagate parent's broadcast flags
2079*c54f35caSApple OSS Distributions 		myChangeFlags = kIOPMParentInitiated | kIOPMDomainDidChange |
2080*c54f35caSApple OSS Distributions 		    (parentChangeFlags & kIOPMRootBroadcastFlags);
2081*c54f35caSApple OSS Distributions 
2082*c54f35caSApple OSS Distributions 		if (kIOPMAOTPower & fPowerStates[maxPowerState].inputPowerFlags) {
2083*c54f35caSApple OSS Distributions 			IOLog("aotPS %s0x%qx[%ld]\n", getName(), getRegistryEntryID(), maxPowerState);
2084*c54f35caSApple OSS Distributions 		}
2085*c54f35caSApple OSS Distributions 
2086*c54f35caSApple OSS Distributions 		result = startPowerChange(
2087*c54f35caSApple OSS Distributions 			/* flags        */ myChangeFlags,
2088*c54f35caSApple OSS Distributions 			/* power state  */ maxPowerState,
2089*c54f35caSApple OSS Distributions 			/* domain flags */ fParentsCurrentPowerFlags,
2090*c54f35caSApple OSS Distributions 			/* connection   */ whichParent,
2091*c54f35caSApple OSS Distributions 			/* parent flags */ 0);
2092*c54f35caSApple OSS Distributions 	}
2093*c54f35caSApple OSS Distributions 
2094*c54f35caSApple OSS Distributions 	// Parent is expecting an ACK from us. If we did not embark on a state
2095*c54f35caSApple OSS Distributions 	// transition, i.e. startPowerChange() returned IOPMAckImplied. We are
2096*c54f35caSApple OSS Distributions 	// still required to issue an ACK to our parent.
2097*c54f35caSApple OSS Distributions 
2098*c54f35caSApple OSS Distributions 	if (IOPMAckImplied == result) {
2099*c54f35caSApple OSS Distributions 		IOService * parent;
2100*c54f35caSApple OSS Distributions 		parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
2101*c54f35caSApple OSS Distributions 		assert(parent);
2102*c54f35caSApple OSS Distributions 		if (parent) {
2103*c54f35caSApple OSS Distributions 			parent->acknowledgePowerChange( whichParent );
2104*c54f35caSApple OSS Distributions 			parent->release();
2105*c54f35caSApple OSS Distributions 		}
2106*c54f35caSApple OSS Distributions 	}
2107*c54f35caSApple OSS Distributions 
2108*c54f35caSApple OSS Distributions 	// If the parent registers its power driver late, then this is the
2109*c54f35caSApple OSS Distributions 	// first opportunity to tell our parent about our desire. Or if the
2110*c54f35caSApple OSS Distributions 	// child's desire changed during a parent change notify.
2111*c54f35caSApple OSS Distributions 
2112*c54f35caSApple OSS Distributions 	if (fControllingDriver &&
2113*c54f35caSApple OSS Distributions 	    ((!savedParentsKnowState && fParentsKnowState) || desireChanged)) {
2114*c54f35caSApple OSS Distributions 		PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState %d\n",
2115*c54f35caSApple OSS Distributions 		    getName(), fParentsKnowState);
2116*c54f35caSApple OSS Distributions 		requestDomainPower( fDesiredPowerState );
2117*c54f35caSApple OSS Distributions 	}
2118*c54f35caSApple OSS Distributions 
2119*c54f35caSApple OSS Distributions exit_no_ack:
2120*c54f35caSApple OSS Distributions 	// Drop the retain from notifyChild().
2121*c54f35caSApple OSS Distributions 	if (whichParent) {
2122*c54f35caSApple OSS Distributions 		whichParent->release();
2123*c54f35caSApple OSS Distributions 	}
2124*c54f35caSApple OSS Distributions }
2125*c54f35caSApple OSS Distributions 
2126*c54f35caSApple OSS Distributions //*********************************************************************************
2127*c54f35caSApple OSS Distributions // [private] setParentInfo
2128*c54f35caSApple OSS Distributions //
2129*c54f35caSApple OSS Distributions // Set our connection data for one specific parent, and then combine all the parent
2130*c54f35caSApple OSS Distributions // data together.
2131*c54f35caSApple OSS Distributions //*********************************************************************************
2132*c54f35caSApple OSS Distributions 
2133*c54f35caSApple OSS Distributions void
setParentInfo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent,bool knowsState)2134*c54f35caSApple OSS Distributions IOService::setParentInfo(
2135*c54f35caSApple OSS Distributions 	IOPMPowerFlags      newPowerFlags,
2136*c54f35caSApple OSS Distributions 	IOPowerConnection * whichParent,
2137*c54f35caSApple OSS Distributions 	bool                knowsState )
2138*c54f35caSApple OSS Distributions {
2139*c54f35caSApple OSS Distributions 	OSIterator *        iter;
2140*c54f35caSApple OSS Distributions 	OSObject *          next;
2141*c54f35caSApple OSS Distributions 	IOPowerConnection * conn;
2142*c54f35caSApple OSS Distributions 
2143*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
2144*c54f35caSApple OSS Distributions 
2145*c54f35caSApple OSS Distributions 	// set our connection data
2146*c54f35caSApple OSS Distributions 	whichParent->setParentCurrentPowerFlags(newPowerFlags);
2147*c54f35caSApple OSS Distributions 	whichParent->setParentKnowsState(knowsState);
2148*c54f35caSApple OSS Distributions 
2149*c54f35caSApple OSS Distributions 	// recompute our parent info
2150*c54f35caSApple OSS Distributions 	fParentsCurrentPowerFlags = 0;
2151*c54f35caSApple OSS Distributions 	fParentsKnowState = true;
2152*c54f35caSApple OSS Distributions 
2153*c54f35caSApple OSS Distributions 	iter = getParentIterator(gIOPowerPlane);
2154*c54f35caSApple OSS Distributions 	if (iter) {
2155*c54f35caSApple OSS Distributions 		while ((next = iter->getNextObject())) {
2156*c54f35caSApple OSS Distributions 			if ((conn = OSDynamicCast(IOPowerConnection, next))) {
2157*c54f35caSApple OSS Distributions 				fParentsKnowState &= conn->parentKnowsState();
2158*c54f35caSApple OSS Distributions 				fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
2159*c54f35caSApple OSS Distributions 			}
2160*c54f35caSApple OSS Distributions 		}
2161*c54f35caSApple OSS Distributions 		iter->release();
2162*c54f35caSApple OSS Distributions 	}
2163*c54f35caSApple OSS Distributions }
2164*c54f35caSApple OSS Distributions 
2165*c54f35caSApple OSS Distributions //******************************************************************************
2166*c54f35caSApple OSS Distributions // [private] trackSystemSleepPreventers
2167*c54f35caSApple OSS Distributions //******************************************************************************
2168*c54f35caSApple OSS Distributions 
2169*c54f35caSApple OSS Distributions void
trackSystemSleepPreventers(IOPMPowerStateIndex oldPowerState,IOPMPowerStateIndex newPowerState,IOPMPowerChangeFlags changeFlags __unused)2170*c54f35caSApple OSS Distributions IOService::trackSystemSleepPreventers(
2171*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex     oldPowerState,
2172*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex     newPowerState,
2173*c54f35caSApple OSS Distributions 	IOPMPowerChangeFlags    changeFlags __unused )
2174*c54f35caSApple OSS Distributions {
2175*c54f35caSApple OSS Distributions 	IOPMPowerFlags  oldCapability, newCapability;
2176*c54f35caSApple OSS Distributions 
2177*c54f35caSApple OSS Distributions 	oldCapability = fPowerStates[oldPowerState].capabilityFlags &
2178*c54f35caSApple OSS Distributions 	    (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2179*c54f35caSApple OSS Distributions 	newCapability = fPowerStates[newPowerState].capabilityFlags &
2180*c54f35caSApple OSS Distributions 	    (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2181*c54f35caSApple OSS Distributions 
2182*c54f35caSApple OSS Distributions 	if (fHeadNoteChangeFlags & kIOPMInitialPowerChange) {
2183*c54f35caSApple OSS Distributions 		oldCapability = 0;
2184*c54f35caSApple OSS Distributions 	}
2185*c54f35caSApple OSS Distributions 	if (oldCapability == newCapability) {
2186*c54f35caSApple OSS Distributions 		return;
2187*c54f35caSApple OSS Distributions 	}
2188*c54f35caSApple OSS Distributions 
2189*c54f35caSApple OSS Distributions 	if ((oldCapability ^ newCapability) & kIOPMPreventIdleSleep) {
2190*c54f35caSApple OSS Distributions 		bool enablePrevention  = ((oldCapability & kIOPMPreventIdleSleep) == 0);
2191*c54f35caSApple OSS Distributions 		bool idleCancelAllowed = getPMRootDomain()->updatePreventIdleSleepList(
2192*c54f35caSApple OSS Distributions 			this, enablePrevention);
2193*c54f35caSApple OSS Distributions #if SUPPORT_IDLE_CANCEL
2194*c54f35caSApple OSS Distributions 		if (idleCancelAllowed && enablePrevention) {
2195*c54f35caSApple OSS Distributions 			IOPMRequest *   cancelRequest;
2196*c54f35caSApple OSS Distributions 
2197*c54f35caSApple OSS Distributions 			cancelRequest = acquirePMRequest( getPMRootDomain(), kIOPMRequestTypeIdleCancel );
2198*c54f35caSApple OSS Distributions 			if (cancelRequest) {
2199*c54f35caSApple OSS Distributions 				submitPMRequest( cancelRequest );
2200*c54f35caSApple OSS Distributions 			}
2201*c54f35caSApple OSS Distributions 		}
2202*c54f35caSApple OSS Distributions #endif
2203*c54f35caSApple OSS Distributions 	}
2204*c54f35caSApple OSS Distributions 
2205*c54f35caSApple OSS Distributions 	if ((oldCapability ^ newCapability) & kIOPMPreventSystemSleep) {
2206*c54f35caSApple OSS Distributions 		getPMRootDomain()->updatePreventSystemSleepList(this,
2207*c54f35caSApple OSS Distributions 		    ((oldCapability & kIOPMPreventSystemSleep) == 0));
2208*c54f35caSApple OSS Distributions 	}
2209*c54f35caSApple OSS Distributions }
2210*c54f35caSApple OSS Distributions 
2211*c54f35caSApple OSS Distributions //*********************************************************************************
2212*c54f35caSApple OSS Distributions // [public] requestPowerDomainState
2213*c54f35caSApple OSS Distributions //
2214*c54f35caSApple OSS Distributions // Called on a power parent when a child's power requirement changes.
2215*c54f35caSApple OSS Distributions //*********************************************************************************
2216*c54f35caSApple OSS Distributions 
2217*c54f35caSApple OSS Distributions IOReturn
requestPowerDomainState(IOPMPowerFlags childRequestPowerFlags,IOPowerConnection * childConnection,unsigned long specification)2218*c54f35caSApple OSS Distributions IOService::requestPowerDomainState(
2219*c54f35caSApple OSS Distributions 	IOPMPowerFlags      childRequestPowerFlags,
2220*c54f35caSApple OSS Distributions 	IOPowerConnection * childConnection,
2221*c54f35caSApple OSS Distributions 	unsigned long       specification )
2222*c54f35caSApple OSS Distributions {
2223*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex order, powerState;
2224*c54f35caSApple OSS Distributions 	IOPMPowerFlags      outputPowerFlags;
2225*c54f35caSApple OSS Distributions 	IOService *         child;
2226*c54f35caSApple OSS Distributions 	IOPMRequest *       subRequest;
2227*c54f35caSApple OSS Distributions 	bool                adjustPower = false;
2228*c54f35caSApple OSS Distributions 
2229*c54f35caSApple OSS Distributions 	if (!initialized) {
2230*c54f35caSApple OSS Distributions 		return IOPMNotYetInitialized;
2231*c54f35caSApple OSS Distributions 	}
2232*c54f35caSApple OSS Distributions 
2233*c54f35caSApple OSS Distributions 	if (gIOPMWorkLoop->onThread() == false) {
2234*c54f35caSApple OSS Distributions 		PM_LOG("%s::requestPowerDomainState\n", getName());
2235*c54f35caSApple OSS Distributions 		return kIOReturnSuccess;
2236*c54f35caSApple OSS Distributions 	}
2237*c54f35caSApple OSS Distributions 
2238*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogRequestDomain, childRequestPowerFlags, specification);
2239*c54f35caSApple OSS Distributions 
2240*c54f35caSApple OSS Distributions 	if (!isChild(childConnection, gIOPowerPlane)) {
2241*c54f35caSApple OSS Distributions 		return kIOReturnNotAttached;
2242*c54f35caSApple OSS Distributions 	}
2243*c54f35caSApple OSS Distributions 
2244*c54f35caSApple OSS Distributions 	if (!fControllingDriver || !fNumberOfPowerStates) {
2245*c54f35caSApple OSS Distributions 		return kIOReturnNotReady;
2246*c54f35caSApple OSS Distributions 	}
2247*c54f35caSApple OSS Distributions 
2248*c54f35caSApple OSS Distributions 	child = (IOService *) childConnection->getChildEntry(gIOPowerPlane);
2249*c54f35caSApple OSS Distributions 	assert(child);
2250*c54f35caSApple OSS Distributions 
2251*c54f35caSApple OSS Distributions 	// Remove flags from child request which we can't possibly supply
2252*c54f35caSApple OSS Distributions 	childRequestPowerFlags &= fMergedOutputPowerFlags;
2253*c54f35caSApple OSS Distributions 
2254*c54f35caSApple OSS Distributions 	// Merge in the power flags contributed by this power parent
2255*c54f35caSApple OSS Distributions 	// at its current or impending power state.
2256*c54f35caSApple OSS Distributions 
2257*c54f35caSApple OSS Distributions 	outputPowerFlags = fPowerStates[fCurrentPowerState].outputPowerFlags;
2258*c54f35caSApple OSS Distributions 	if (fMachineState != kIOPM_Finished) {
2259*c54f35caSApple OSS Distributions 		if (IS_POWER_DROP && !IS_ROOT_DOMAIN) {
2260*c54f35caSApple OSS Distributions 			// Use the lower power state when dropping power.
2261*c54f35caSApple OSS Distributions 			// Must be careful since a power drop can be cancelled
2262*c54f35caSApple OSS Distributions 			// from the following states:
2263*c54f35caSApple OSS Distributions 			// - kIOPM_OurChangeTellClientsPowerDown
2264*c54f35caSApple OSS Distributions 			// - kIOPM_OurChangeTellPriorityClientsPowerDown
2265*c54f35caSApple OSS Distributions 			//
2266*c54f35caSApple OSS Distributions 			// The child must not wait for this parent to raise power
2267*c54f35caSApple OSS Distributions 			// if the power drop was cancelled. The solution is to cancel
2268*c54f35caSApple OSS Distributions 			// the power drop if possible, then schedule an adjustment to
2269*c54f35caSApple OSS Distributions 			// re-evaluate the parent's power state.
2270*c54f35caSApple OSS Distributions 			//
2271*c54f35caSApple OSS Distributions 			// Root domain is excluded to avoid idle sleep issues. And allow
2272*c54f35caSApple OSS Distributions 			// root domain children to pop up when system is going to sleep.
2273*c54f35caSApple OSS Distributions 
2274*c54f35caSApple OSS Distributions 			if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown) ||
2275*c54f35caSApple OSS Distributions 			    (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)) {
2276*c54f35caSApple OSS Distributions 				fDoNotPowerDown = true; // cancel power drop
2277*c54f35caSApple OSS Distributions 				adjustPower     = true;// schedule an adjustment
2278*c54f35caSApple OSS Distributions 				PM_LOG1("%s: power drop cancelled in state %u by %s\n",
2279*c54f35caSApple OSS Distributions 				    getName(), fMachineState, child->getName());
2280*c54f35caSApple OSS Distributions 			} else {
2281*c54f35caSApple OSS Distributions 				// Beyond cancellation point, report the impending state.
2282*c54f35caSApple OSS Distributions 				outputPowerFlags =
2283*c54f35caSApple OSS Distributions 				    fPowerStates[fHeadNotePowerState].outputPowerFlags;
2284*c54f35caSApple OSS Distributions 			}
2285*c54f35caSApple OSS Distributions 		} else if (IS_POWER_RISE) {
2286*c54f35caSApple OSS Distributions 			// When raising power, must report the output power flags from
2287*c54f35caSApple OSS Distributions 			// child's perspective. A child power request may arrive while
2288*c54f35caSApple OSS Distributions 			// parent is transitioning upwards. If a request arrives after
2289*c54f35caSApple OSS Distributions 			// setParentInfo() has already recorded the output power flags
2290*c54f35caSApple OSS Distributions 			// for the next power state, then using the power supplied by
2291*c54f35caSApple OSS Distributions 			// fCurrentPowerState is incorrect, and might cause the child
2292*c54f35caSApple OSS Distributions 			// to wait when it should not.
2293*c54f35caSApple OSS Distributions 
2294*c54f35caSApple OSS Distributions 			outputPowerFlags = childConnection->parentCurrentPowerFlags();
2295*c54f35caSApple OSS Distributions 		}
2296*c54f35caSApple OSS Distributions 	}
2297*c54f35caSApple OSS Distributions 	child->fHeadNoteDomainTargetFlags |= outputPowerFlags;
2298*c54f35caSApple OSS Distributions 
2299*c54f35caSApple OSS Distributions 	// Map child's requested power flags to one of our power state.
2300*c54f35caSApple OSS Distributions 
2301*c54f35caSApple OSS Distributions 	for (order = 0; order < fNumberOfPowerStates; order++) {
2302*c54f35caSApple OSS Distributions 		powerState = fPowerStates[order].stateOrderToIndex;
2303*c54f35caSApple OSS Distributions 		if ((fPowerStates[powerState].outputPowerFlags & childRequestPowerFlags)
2304*c54f35caSApple OSS Distributions 		    == childRequestPowerFlags) {
2305*c54f35caSApple OSS Distributions 			break;
2306*c54f35caSApple OSS Distributions 		}
2307*c54f35caSApple OSS Distributions 	}
2308*c54f35caSApple OSS Distributions 	if (order >= fNumberOfPowerStates) {
2309*c54f35caSApple OSS Distributions 		powerState = kPowerStateZero;
2310*c54f35caSApple OSS Distributions 	}
2311*c54f35caSApple OSS Distributions 
2312*c54f35caSApple OSS Distributions 	// Conditions that warrants a power adjustment on this parent.
2313*c54f35caSApple OSS Distributions 	// Adjust power will also propagate any changes to the child's
2314*c54f35caSApple OSS Distributions 	// prevent idle/sleep flags towards the root domain.
2315*c54f35caSApple OSS Distributions 
2316*c54f35caSApple OSS Distributions 	if (!childConnection->childHasRequestedPower() ||
2317*c54f35caSApple OSS Distributions 	    (powerState != childConnection->getDesiredDomainState())) {
2318*c54f35caSApple OSS Distributions 		adjustPower = true;
2319*c54f35caSApple OSS Distributions 	}
2320*c54f35caSApple OSS Distributions 
2321*c54f35caSApple OSS Distributions #if ENABLE_DEBUG_LOGS
2322*c54f35caSApple OSS Distributions 	if (adjustPower) {
2323*c54f35caSApple OSS Distributions 		PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
2324*c54f35caSApple OSS Distributions 		    getName(), child->getName(),
2325*c54f35caSApple OSS Distributions 		    !childConnection->childHasRequestedPower(),
2326*c54f35caSApple OSS Distributions 		    (uint32_t) childConnection->getDesiredDomainState(),
2327*c54f35caSApple OSS Distributions 		    (uint32_t) powerState);
2328*c54f35caSApple OSS Distributions 	}
2329*c54f35caSApple OSS Distributions #endif
2330*c54f35caSApple OSS Distributions 
2331*c54f35caSApple OSS Distributions 	// Record the child's desires on the connection.
2332*c54f35caSApple OSS Distributions 	childConnection->setChildHasRequestedPower();
2333*c54f35caSApple OSS Distributions 	childConnection->setDesiredDomainState( powerState );
2334*c54f35caSApple OSS Distributions 
2335*c54f35caSApple OSS Distributions 	// Schedule a request to re-evaluate all children desires and
2336*c54f35caSApple OSS Distributions 	// adjust power state. Submit a request if one wasn't pending,
2337*c54f35caSApple OSS Distributions 	// or if the current request is part of a call tree.
2338*c54f35caSApple OSS Distributions 
2339*c54f35caSApple OSS Distributions 	if (adjustPower && !fDeviceOverrideEnabled &&
2340*c54f35caSApple OSS Distributions 	    (!fAdjustPowerScheduled || gIOPMRequest->getRootRequest())) {
2341*c54f35caSApple OSS Distributions 		subRequest = acquirePMRequest(
2342*c54f35caSApple OSS Distributions 			this, kIOPMRequestTypeAdjustPowerState, gIOPMRequest );
2343*c54f35caSApple OSS Distributions 		if (subRequest) {
2344*c54f35caSApple OSS Distributions 			submitPMRequest( subRequest );
2345*c54f35caSApple OSS Distributions 			fAdjustPowerScheduled = true;
2346*c54f35caSApple OSS Distributions 		}
2347*c54f35caSApple OSS Distributions 	}
2348*c54f35caSApple OSS Distributions 
2349*c54f35caSApple OSS Distributions 	return kIOReturnSuccess;
2350*c54f35caSApple OSS Distributions }
2351*c54f35caSApple OSS Distributions 
2352*c54f35caSApple OSS Distributions //*********************************************************************************
2353*c54f35caSApple OSS Distributions // [public] temporaryPowerClampOn
2354*c54f35caSApple OSS Distributions //
2355*c54f35caSApple OSS Distributions // A power domain wants to be clamped to max power until it has children which
2356*c54f35caSApple OSS Distributions // will then determine the power domain state.
2357*c54f35caSApple OSS Distributions //
2358*c54f35caSApple OSS Distributions // We enter the highest state until addPowerChild is called.
2359*c54f35caSApple OSS Distributions //*********************************************************************************
2360*c54f35caSApple OSS Distributions 
2361*c54f35caSApple OSS Distributions IOReturn
temporaryPowerClampOn(void)2362*c54f35caSApple OSS Distributions IOService::temporaryPowerClampOn( void )
2363*c54f35caSApple OSS Distributions {
2364*c54f35caSApple OSS Distributions 	return requestPowerState( gIOPMPowerClientChildProxy, kIOPMPowerStateMax );
2365*c54f35caSApple OSS Distributions }
2366*c54f35caSApple OSS Distributions 
2367*c54f35caSApple OSS Distributions //*********************************************************************************
2368*c54f35caSApple OSS Distributions // [public] makeUsable
2369*c54f35caSApple OSS Distributions //
2370*c54f35caSApple OSS Distributions // Some client of our device is asking that we become usable.  Although
2371*c54f35caSApple OSS Distributions // this has not come from a subclassed device object, treat it exactly
2372*c54f35caSApple OSS Distributions // as if it had.  In this way, subsequent requests for lower power from
2373*c54f35caSApple OSS Distributions // a subclassed device object will pre-empt this request.
2374*c54f35caSApple OSS Distributions //
2375*c54f35caSApple OSS Distributions // We treat this as a subclass object request to switch to the
2376*c54f35caSApple OSS Distributions // highest power state.
2377*c54f35caSApple OSS Distributions //*********************************************************************************
2378*c54f35caSApple OSS Distributions 
2379*c54f35caSApple OSS Distributions IOReturn
makeUsable(void)2380*c54f35caSApple OSS Distributions IOService::makeUsable( void )
2381*c54f35caSApple OSS Distributions {
2382*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogMakeUsable, 0, 0);
2383*c54f35caSApple OSS Distributions 	return requestPowerState( gIOPMPowerClientDevice, kIOPMPowerStateMax );
2384*c54f35caSApple OSS Distributions }
2385*c54f35caSApple OSS Distributions 
2386*c54f35caSApple OSS Distributions //*********************************************************************************
2387*c54f35caSApple OSS Distributions // [public] currentCapability
2388*c54f35caSApple OSS Distributions //*********************************************************************************
2389*c54f35caSApple OSS Distributions 
2390*c54f35caSApple OSS Distributions IOPMPowerFlags
currentCapability(void)2391*c54f35caSApple OSS Distributions IOService::currentCapability( void )
2392*c54f35caSApple OSS Distributions {
2393*c54f35caSApple OSS Distributions 	if (!initialized) {
2394*c54f35caSApple OSS Distributions 		return IOPMNotPowerManaged;
2395*c54f35caSApple OSS Distributions 	}
2396*c54f35caSApple OSS Distributions 
2397*c54f35caSApple OSS Distributions 	return fCurrentCapabilityFlags;
2398*c54f35caSApple OSS Distributions }
2399*c54f35caSApple OSS Distributions 
2400*c54f35caSApple OSS Distributions //*********************************************************************************
2401*c54f35caSApple OSS Distributions // [public] changePowerStateTo
2402*c54f35caSApple OSS Distributions //
2403*c54f35caSApple OSS Distributions // Called by our power-controlling driver to change power state. The new desired
2404*c54f35caSApple OSS Distributions // power state is computed and compared against the current power state. If those
2405*c54f35caSApple OSS Distributions // power states differ, then a power state change is initiated.
2406*c54f35caSApple OSS Distributions //*********************************************************************************
2407*c54f35caSApple OSS Distributions 
2408*c54f35caSApple OSS Distributions IOReturn
changePowerStateTo(unsigned long ordinal)2409*c54f35caSApple OSS Distributions IOService::changePowerStateTo( unsigned long ordinal )
2410*c54f35caSApple OSS Distributions {
2411*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2412*c54f35caSApple OSS Distributions 	return requestPowerState( gIOPMPowerClientDriver, ordinal );
2413*c54f35caSApple OSS Distributions }
2414*c54f35caSApple OSS Distributions 
2415*c54f35caSApple OSS Distributions //*********************************************************************************
2416*c54f35caSApple OSS Distributions // [protected] changePowerStateToPriv
2417*c54f35caSApple OSS Distributions //
2418*c54f35caSApple OSS Distributions // Called by our driver subclass to change power state. The new desired power
2419*c54f35caSApple OSS Distributions // state is computed and compared against the current power state. If those
2420*c54f35caSApple OSS Distributions // power states differ, then a power state change is initiated.
2421*c54f35caSApple OSS Distributions //*********************************************************************************
2422*c54f35caSApple OSS Distributions 
2423*c54f35caSApple OSS Distributions IOReturn
changePowerStateToPriv(unsigned long ordinal)2424*c54f35caSApple OSS Distributions IOService::changePowerStateToPriv( unsigned long ordinal )
2425*c54f35caSApple OSS Distributions {
2426*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2427*c54f35caSApple OSS Distributions 	return requestPowerState( gIOPMPowerClientDevice, ordinal );
2428*c54f35caSApple OSS Distributions }
2429*c54f35caSApple OSS Distributions 
2430*c54f35caSApple OSS Distributions //*********************************************************************************
2431*c54f35caSApple OSS Distributions // [public] changePowerStateWithOverrideTo
2432*c54f35caSApple OSS Distributions //
2433*c54f35caSApple OSS Distributions // Called by our driver subclass to change power state. The new desired power
2434*c54f35caSApple OSS Distributions // state is computed and compared against the current power state. If those
2435*c54f35caSApple OSS Distributions // power states differ, then a power state change is initiated.
2436*c54f35caSApple OSS Distributions // Override enforced - Children and Driver desires are ignored.
2437*c54f35caSApple OSS Distributions //*********************************************************************************
2438*c54f35caSApple OSS Distributions 
2439*c54f35caSApple OSS Distributions IOReturn
changePowerStateWithOverrideTo(IOPMPowerStateIndex ordinal,IOPMRequestTag tag)2440*c54f35caSApple OSS Distributions IOService::changePowerStateWithOverrideTo( IOPMPowerStateIndex ordinal,
2441*c54f35caSApple OSS Distributions     IOPMRequestTag tag )
2442*c54f35caSApple OSS Distributions {
2443*c54f35caSApple OSS Distributions 	IOPMRequest * request;
2444*c54f35caSApple OSS Distributions 
2445*c54f35caSApple OSS Distributions 	if (!initialized) {
2446*c54f35caSApple OSS Distributions 		return kIOPMNotYetInitialized;
2447*c54f35caSApple OSS Distributions 	}
2448*c54f35caSApple OSS Distributions 
2449*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2450*c54f35caSApple OSS Distributions 
2451*c54f35caSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride );
2452*c54f35caSApple OSS Distributions 	if (!request) {
2453*c54f35caSApple OSS Distributions 		return kIOReturnNoMemory;
2454*c54f35caSApple OSS Distributions 	}
2455*c54f35caSApple OSS Distributions 
2456*c54f35caSApple OSS Distributions 	gIOPMPowerClientDevice->retain();
2457*c54f35caSApple OSS Distributions 	request->fTag  = tag;
2458*c54f35caSApple OSS Distributions 	request->fArg0 = (void *) ordinal;
2459*c54f35caSApple OSS Distributions 	request->fArg1 = (void *) gIOPMPowerClientDevice;
2460*c54f35caSApple OSS Distributions 	request->fArg2 = NULL;
2461*c54f35caSApple OSS Distributions #if NOT_READY
2462*c54f35caSApple OSS Distributions 	if (action) {
2463*c54f35caSApple OSS Distributions 		request->installCompletionAction( action, target, param );
2464*c54f35caSApple OSS Distributions 	}
2465*c54f35caSApple OSS Distributions #endif
2466*c54f35caSApple OSS Distributions 
2467*c54f35caSApple OSS Distributions 	// Prevent needless downwards power transitions by clamping power
2468*c54f35caSApple OSS Distributions 	// until the scheduled request is executed.
2469*c54f35caSApple OSS Distributions 	//
2470*c54f35caSApple OSS Distributions 	// TODO: review fOverrideMaxPowerState
2471*c54f35caSApple OSS Distributions 
2472*c54f35caSApple OSS Distributions 	if (gIOPMWorkLoop->inGate() && (ordinal < fNumberOfPowerStates)) {
2473*c54f35caSApple OSS Distributions 		fTempClampPowerState = StateMax(fTempClampPowerState, ordinal);
2474*c54f35caSApple OSS Distributions 		fTempClampCount++;
2475*c54f35caSApple OSS Distributions 		request->fArg2 = (void *)(uintptr_t) true;
2476*c54f35caSApple OSS Distributions 
2477*c54f35caSApple OSS Distributions 		// Place a power state ceiling to prevent any transition to a
2478*c54f35caSApple OSS Distributions 		// power state higher than fOverrideMaxPowerState.
2479*c54f35caSApple OSS Distributions 		fOverrideMaxPowerState = ordinal;
2480*c54f35caSApple OSS Distributions 	}
2481*c54f35caSApple OSS Distributions 
2482*c54f35caSApple OSS Distributions 	submitPMRequest( request );
2483*c54f35caSApple OSS Distributions 	return IOPMNoErr;
2484*c54f35caSApple OSS Distributions }
2485*c54f35caSApple OSS Distributions 
2486*c54f35caSApple OSS Distributions //*********************************************************************************
2487*c54f35caSApple OSS Distributions // Tagged form of changePowerStateTo()
2488*c54f35caSApple OSS Distributions //*********************************************************************************
2489*c54f35caSApple OSS Distributions 
2490*c54f35caSApple OSS Distributions IOReturn
changePowerStateWithTagTo(IOPMPowerStateIndex ordinal,IOPMRequestTag tag)2491*c54f35caSApple OSS Distributions IOService::changePowerStateWithTagTo( IOPMPowerStateIndex ordinal, IOPMRequestTag tag )
2492*c54f35caSApple OSS Distributions {
2493*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogChangeStateTo, ordinal, tag);
2494*c54f35caSApple OSS Distributions 	return requestPowerState(gIOPMPowerClientDriver, ordinal, tag);
2495*c54f35caSApple OSS Distributions }
2496*c54f35caSApple OSS Distributions 
2497*c54f35caSApple OSS Distributions //*********************************************************************************
2498*c54f35caSApple OSS Distributions // Tagged form of changePowerStateToPriv()
2499*c54f35caSApple OSS Distributions //*********************************************************************************
2500*c54f35caSApple OSS Distributions 
2501*c54f35caSApple OSS Distributions IOReturn
changePowerStateWithTagToPriv(unsigned long ordinal,IOPMRequestTag tag)2502*c54f35caSApple OSS Distributions IOService::changePowerStateWithTagToPriv( unsigned long ordinal, IOPMRequestTag tag )
2503*c54f35caSApple OSS Distributions {
2504*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogChangeStateToPriv, ordinal, tag);
2505*c54f35caSApple OSS Distributions 	return requestPowerState(gIOPMPowerClientDevice, ordinal, tag);
2506*c54f35caSApple OSS Distributions }
2507*c54f35caSApple OSS Distributions 
2508*c54f35caSApple OSS Distributions //*********************************************************************************
2509*c54f35caSApple OSS Distributions // [public] changePowerStateForRootDomain
2510*c54f35caSApple OSS Distributions //
2511*c54f35caSApple OSS Distributions // Adjust the root domain's power desire on the target
2512*c54f35caSApple OSS Distributions //*********************************************************************************
2513*c54f35caSApple OSS Distributions 
2514*c54f35caSApple OSS Distributions IOReturn
changePowerStateForRootDomain(IOPMPowerStateIndex ordinal)2515*c54f35caSApple OSS Distributions IOService::changePowerStateForRootDomain( IOPMPowerStateIndex ordinal )
2516*c54f35caSApple OSS Distributions {
2517*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogChangeStateForRootDomain, ordinal, 0);
2518*c54f35caSApple OSS Distributions 	return requestPowerState( gIOPMPowerClientRootDomain, ordinal );
2519*c54f35caSApple OSS Distributions }
2520*c54f35caSApple OSS Distributions 
2521*c54f35caSApple OSS Distributions //*********************************************************************************
2522*c54f35caSApple OSS Distributions // [public for PMRD] quiescePowerTree
2523*c54f35caSApple OSS Distributions //
2524*c54f35caSApple OSS Distributions // For root domain to issue a request to quiesce the power tree.
2525*c54f35caSApple OSS Distributions // Supplied callback invoked upon completion.
2526*c54f35caSApple OSS Distributions //*********************************************************************************
2527*c54f35caSApple OSS Distributions 
2528*c54f35caSApple OSS Distributions IOReturn
quiescePowerTree(void * target,IOPMCompletionAction action,void * param)2529*c54f35caSApple OSS Distributions IOService::quiescePowerTree(
2530*c54f35caSApple OSS Distributions 	void * target, IOPMCompletionAction action, void * param )
2531*c54f35caSApple OSS Distributions {
2532*c54f35caSApple OSS Distributions 	IOPMRequest * request;
2533*c54f35caSApple OSS Distributions 
2534*c54f35caSApple OSS Distributions 	if (!initialized) {
2535*c54f35caSApple OSS Distributions 		return kIOPMNotYetInitialized;
2536*c54f35caSApple OSS Distributions 	}
2537*c54f35caSApple OSS Distributions 	if (!target || !action) {
2538*c54f35caSApple OSS Distributions 		return kIOReturnBadArgument;
2539*c54f35caSApple OSS Distributions 	}
2540*c54f35caSApple OSS Distributions 
2541*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogQuiescePowerTree, 0, 0);
2542*c54f35caSApple OSS Distributions 
2543*c54f35caSApple OSS Distributions 	// Target the root node instead of root domain. This is to avoid blocking
2544*c54f35caSApple OSS Distributions 	// the quiesce request behind an existing root domain request in the work
2545*c54f35caSApple OSS Distributions 	// queue. Root parent and root domain requests in the work queue must not
2546*c54f35caSApple OSS Distributions 	// block the completion of the quiesce request.
2547*c54f35caSApple OSS Distributions 
2548*c54f35caSApple OSS Distributions 	request = acquirePMRequest(gIOPMRootNode, kIOPMRequestTypeQuiescePowerTree);
2549*c54f35caSApple OSS Distributions 	if (!request) {
2550*c54f35caSApple OSS Distributions 		return kIOReturnNoMemory;
2551*c54f35caSApple OSS Distributions 	}
2552*c54f35caSApple OSS Distributions 
2553*c54f35caSApple OSS Distributions 	request->installCompletionAction(target, action, param);
2554*c54f35caSApple OSS Distributions 
2555*c54f35caSApple OSS Distributions 	// Submit through the normal request flow. This will make sure any request
2556*c54f35caSApple OSS Distributions 	// already in the request queue will get pushed over to the work queue for
2557*c54f35caSApple OSS Distributions 	// execution. Any request submitted after this request may not be serviced.
2558*c54f35caSApple OSS Distributions 
2559*c54f35caSApple OSS Distributions 	submitPMRequest( request );
2560*c54f35caSApple OSS Distributions 	return kIOReturnSuccess;
2561*c54f35caSApple OSS Distributions }
2562*c54f35caSApple OSS Distributions 
2563*c54f35caSApple OSS Distributions //*********************************************************************************
2564*c54f35caSApple OSS Distributions // [private] requestPowerState
2565*c54f35caSApple OSS Distributions //*********************************************************************************
2566*c54f35caSApple OSS Distributions 
2567*c54f35caSApple OSS Distributions IOReturn
requestPowerState(const OSSymbol * client,IOPMPowerStateIndex state,IOPMRequestTag tag)2568*c54f35caSApple OSS Distributions IOService::requestPowerState(
2569*c54f35caSApple OSS Distributions 	const OSSymbol *      client,
2570*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex   state,
2571*c54f35caSApple OSS Distributions 	IOPMRequestTag        tag )
2572*c54f35caSApple OSS Distributions {
2573*c54f35caSApple OSS Distributions 	IOPMRequest * request;
2574*c54f35caSApple OSS Distributions 
2575*c54f35caSApple OSS Distributions 	if (!client || (state > UINT_MAX)) {
2576*c54f35caSApple OSS Distributions 		return kIOReturnBadArgument;
2577*c54f35caSApple OSS Distributions 	}
2578*c54f35caSApple OSS Distributions 	if (!initialized) {
2579*c54f35caSApple OSS Distributions 		return kIOPMNotYetInitialized;
2580*c54f35caSApple OSS Distributions 	}
2581*c54f35caSApple OSS Distributions 
2582*c54f35caSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerState );
2583*c54f35caSApple OSS Distributions 	if (!request) {
2584*c54f35caSApple OSS Distributions 		return kIOReturnNoMemory;
2585*c54f35caSApple OSS Distributions 	}
2586*c54f35caSApple OSS Distributions 
2587*c54f35caSApple OSS Distributions 	client->retain();
2588*c54f35caSApple OSS Distributions 	request->fTag  = tag;
2589*c54f35caSApple OSS Distributions 	request->fArg0 = (void *)(uintptr_t) state;
2590*c54f35caSApple OSS Distributions 	request->fArg1 = (void *)            client;
2591*c54f35caSApple OSS Distributions 	request->fArg2 = NULL;
2592*c54f35caSApple OSS Distributions #if NOT_READY
2593*c54f35caSApple OSS Distributions 	if (action) {
2594*c54f35caSApple OSS Distributions 		request->installCompletionAction( action, target, param );
2595*c54f35caSApple OSS Distributions 	}
2596*c54f35caSApple OSS Distributions #endif
2597*c54f35caSApple OSS Distributions 
2598*c54f35caSApple OSS Distributions 	// Prevent needless downwards power transitions by clamping power
2599*c54f35caSApple OSS Distributions 	// until the scheduled request is executed.
2600*c54f35caSApple OSS Distributions 
2601*c54f35caSApple OSS Distributions 	if (gIOPMWorkLoop->inGate() && (state < fNumberOfPowerStates)) {
2602*c54f35caSApple OSS Distributions 		fTempClampPowerState = StateMax(fTempClampPowerState, state);
2603*c54f35caSApple OSS Distributions 		fTempClampCount++;
2604*c54f35caSApple OSS Distributions 		request->fArg2 = (void *)(uintptr_t) true;
2605*c54f35caSApple OSS Distributions 	}
2606*c54f35caSApple OSS Distributions 
2607*c54f35caSApple OSS Distributions 	submitPMRequest( request );
2608*c54f35caSApple OSS Distributions 	return IOPMNoErr;
2609*c54f35caSApple OSS Distributions }
2610*c54f35caSApple OSS Distributions 
2611*c54f35caSApple OSS Distributions //*********************************************************************************
2612*c54f35caSApple OSS Distributions // [private] handleRequestPowerState
2613*c54f35caSApple OSS Distributions //*********************************************************************************
2614*c54f35caSApple OSS Distributions 
2615*c54f35caSApple OSS Distributions void
handleRequestPowerState(IOPMRequest * request)2616*c54f35caSApple OSS Distributions IOService::handleRequestPowerState( IOPMRequest * request )
2617*c54f35caSApple OSS Distributions {
2618*c54f35caSApple OSS Distributions 	const OSSymbol * client   = (const OSSymbol *)    request->fArg1;
2619*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex state = (IOPMPowerStateIndex) request->fArg0;
2620*c54f35caSApple OSS Distributions 
2621*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
2622*c54f35caSApple OSS Distributions 	if (request->fArg2) {
2623*c54f35caSApple OSS Distributions 		assert(fTempClampCount != 0);
2624*c54f35caSApple OSS Distributions 		if (fTempClampCount) {
2625*c54f35caSApple OSS Distributions 			fTempClampCount--;
2626*c54f35caSApple OSS Distributions 		}
2627*c54f35caSApple OSS Distributions 		if (!fTempClampCount) {
2628*c54f35caSApple OSS Distributions 			fTempClampPowerState = kPowerStateZero;
2629*c54f35caSApple OSS Distributions 		}
2630*c54f35caSApple OSS Distributions 	}
2631*c54f35caSApple OSS Distributions 
2632*c54f35caSApple OSS Distributions 	if (fNumberOfPowerStates && (state >= fNumberOfPowerStates)) {
2633*c54f35caSApple OSS Distributions 		state = fHighestPowerState;
2634*c54f35caSApple OSS Distributions 	}
2635*c54f35caSApple OSS Distributions 
2636*c54f35caSApple OSS Distributions 	// The power suppression due to changePowerStateWithOverrideTo() expires
2637*c54f35caSApple OSS Distributions 	// upon the next "device" power request - changePowerStateToPriv().
2638*c54f35caSApple OSS Distributions 
2639*c54f35caSApple OSS Distributions 	if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride) &&
2640*c54f35caSApple OSS Distributions 	    (client == gIOPMPowerClientDevice)) {
2641*c54f35caSApple OSS Distributions 		fOverrideMaxPowerState = kIOPMPowerStateMax;
2642*c54f35caSApple OSS Distributions 	}
2643*c54f35caSApple OSS Distributions 
2644*c54f35caSApple OSS Distributions 	if ((state == kPowerStateZero) &&
2645*c54f35caSApple OSS Distributions 	    (client != gIOPMPowerClientDevice) &&
2646*c54f35caSApple OSS Distributions 	    (client != gIOPMPowerClientDriver) &&
2647*c54f35caSApple OSS Distributions 	    (client != gIOPMPowerClientChildProxy)) {
2648*c54f35caSApple OSS Distributions 		removePowerClient(client);
2649*c54f35caSApple OSS Distributions 	} else {
2650*c54f35caSApple OSS Distributions 		updatePowerClient(client, state);
2651*c54f35caSApple OSS Distributions 	}
2652*c54f35caSApple OSS Distributions 
2653*c54f35caSApple OSS Distributions 	adjustPowerState();
2654*c54f35caSApple OSS Distributions 	client->release();
2655*c54f35caSApple OSS Distributions }
2656*c54f35caSApple OSS Distributions 
2657*c54f35caSApple OSS Distributions //*********************************************************************************
2658*c54f35caSApple OSS Distributions // [private] Helper functions to update/remove power clients.
2659*c54f35caSApple OSS Distributions //*********************************************************************************
2660*c54f35caSApple OSS Distributions 
2661*c54f35caSApple OSS Distributions void
updatePowerClient(const OSSymbol * client,IOPMPowerStateIndex powerState)2662*c54f35caSApple OSS Distributions IOService::updatePowerClient( const OSSymbol * client, IOPMPowerStateIndex powerState )
2663*c54f35caSApple OSS Distributions {
2664*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex oldPowerState = kPowerStateZero;
2665*c54f35caSApple OSS Distributions 
2666*c54f35caSApple OSS Distributions 	if (powerState > UINT_MAX) {
2667*c54f35caSApple OSS Distributions 		assert(false);
2668*c54f35caSApple OSS Distributions 		return;
2669*c54f35caSApple OSS Distributions 	}
2670*c54f35caSApple OSS Distributions 
2671*c54f35caSApple OSS Distributions 	if (!fPowerClients) {
2672*c54f35caSApple OSS Distributions 		fPowerClients = OSDictionary::withCapacity(4);
2673*c54f35caSApple OSS Distributions 	}
2674*c54f35caSApple OSS Distributions 	if (fPowerClients && client) {
2675*c54f35caSApple OSS Distributions 		OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2676*c54f35caSApple OSS Distributions 		if (num) {
2677*c54f35caSApple OSS Distributions 			oldPowerState = num->unsigned32BitValue();
2678*c54f35caSApple OSS Distributions 			num->setValue(powerState);
2679*c54f35caSApple OSS Distributions 		} else {
2680*c54f35caSApple OSS Distributions 			num = OSNumber::withNumber(powerState, 32);
2681*c54f35caSApple OSS Distributions 			if (num) {
2682*c54f35caSApple OSS Distributions 				fPowerClients->setObject(client, num);
2683*c54f35caSApple OSS Distributions 				num->release();
2684*c54f35caSApple OSS Distributions 			}
2685*c54f35caSApple OSS Distributions 		}
2686*c54f35caSApple OSS Distributions 
2687*c54f35caSApple OSS Distributions 		PM_ACTION_CLIENT(actionUpdatePowerClient, client, oldPowerState, powerState);
2688*c54f35caSApple OSS Distributions 	}
2689*c54f35caSApple OSS Distributions }
2690*c54f35caSApple OSS Distributions 
2691*c54f35caSApple OSS Distributions void
removePowerClient(const OSSymbol * client)2692*c54f35caSApple OSS Distributions IOService::removePowerClient( const OSSymbol * client )
2693*c54f35caSApple OSS Distributions {
2694*c54f35caSApple OSS Distributions 	if (fPowerClients && client) {
2695*c54f35caSApple OSS Distributions 		fPowerClients->removeObject(client);
2696*c54f35caSApple OSS Distributions 	}
2697*c54f35caSApple OSS Distributions }
2698*c54f35caSApple OSS Distributions 
2699*c54f35caSApple OSS Distributions IOPMPowerStateIndex
getPowerStateForClient(const OSSymbol * client)2700*c54f35caSApple OSS Distributions IOService::getPowerStateForClient( const OSSymbol * client )
2701*c54f35caSApple OSS Distributions {
2702*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex powerState = kPowerStateZero;
2703*c54f35caSApple OSS Distributions 
2704*c54f35caSApple OSS Distributions 	if (fPowerClients && client) {
2705*c54f35caSApple OSS Distributions 		OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2706*c54f35caSApple OSS Distributions 		if (num) {
2707*c54f35caSApple OSS Distributions 			powerState = num->unsigned32BitValue();
2708*c54f35caSApple OSS Distributions 		}
2709*c54f35caSApple OSS Distributions 	}
2710*c54f35caSApple OSS Distributions 	return powerState;
2711*c54f35caSApple OSS Distributions }
2712*c54f35caSApple OSS Distributions 
2713*c54f35caSApple OSS Distributions //*********************************************************************************
2714*c54f35caSApple OSS Distributions // [protected] powerOverrideOnPriv
2715*c54f35caSApple OSS Distributions //*********************************************************************************
2716*c54f35caSApple OSS Distributions 
2717*c54f35caSApple OSS Distributions IOReturn
powerOverrideOnPriv(void)2718*c54f35caSApple OSS Distributions IOService::powerOverrideOnPriv( void )
2719*c54f35caSApple OSS Distributions {
2720*c54f35caSApple OSS Distributions 	IOPMRequest * request;
2721*c54f35caSApple OSS Distributions 
2722*c54f35caSApple OSS Distributions 	if (!initialized) {
2723*c54f35caSApple OSS Distributions 		return IOPMNotYetInitialized;
2724*c54f35caSApple OSS Distributions 	}
2725*c54f35caSApple OSS Distributions 
2726*c54f35caSApple OSS Distributions 	if (gIOPMWorkLoop->inGate()) {
2727*c54f35caSApple OSS Distributions 		fDeviceOverrideEnabled = true;
2728*c54f35caSApple OSS Distributions 		return IOPMNoErr;
2729*c54f35caSApple OSS Distributions 	}
2730*c54f35caSApple OSS Distributions 
2731*c54f35caSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2732*c54f35caSApple OSS Distributions 	if (!request) {
2733*c54f35caSApple OSS Distributions 		return kIOReturnNoMemory;
2734*c54f35caSApple OSS Distributions 	}
2735*c54f35caSApple OSS Distributions 
2736*c54f35caSApple OSS Distributions 	submitPMRequest( request );
2737*c54f35caSApple OSS Distributions 	return IOPMNoErr;
2738*c54f35caSApple OSS Distributions }
2739*c54f35caSApple OSS Distributions 
2740*c54f35caSApple OSS Distributions //*********************************************************************************
2741*c54f35caSApple OSS Distributions // [protected] powerOverrideOffPriv
2742*c54f35caSApple OSS Distributions //*********************************************************************************
2743*c54f35caSApple OSS Distributions 
2744*c54f35caSApple OSS Distributions IOReturn
powerOverrideOffPriv(void)2745*c54f35caSApple OSS Distributions IOService::powerOverrideOffPriv( void )
2746*c54f35caSApple OSS Distributions {
2747*c54f35caSApple OSS Distributions 	IOPMRequest * request;
2748*c54f35caSApple OSS Distributions 
2749*c54f35caSApple OSS Distributions 	if (!initialized) {
2750*c54f35caSApple OSS Distributions 		return IOPMNotYetInitialized;
2751*c54f35caSApple OSS Distributions 	}
2752*c54f35caSApple OSS Distributions 
2753*c54f35caSApple OSS Distributions 	if (gIOPMWorkLoop->inGate()) {
2754*c54f35caSApple OSS Distributions 		fDeviceOverrideEnabled = false;
2755*c54f35caSApple OSS Distributions 		return IOPMNoErr;
2756*c54f35caSApple OSS Distributions 	}
2757*c54f35caSApple OSS Distributions 
2758*c54f35caSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2759*c54f35caSApple OSS Distributions 	if (!request) {
2760*c54f35caSApple OSS Distributions 		return kIOReturnNoMemory;
2761*c54f35caSApple OSS Distributions 	}
2762*c54f35caSApple OSS Distributions 
2763*c54f35caSApple OSS Distributions 	submitPMRequest( request );
2764*c54f35caSApple OSS Distributions 	return IOPMNoErr;
2765*c54f35caSApple OSS Distributions }
2766*c54f35caSApple OSS Distributions 
2767*c54f35caSApple OSS Distributions //*********************************************************************************
2768*c54f35caSApple OSS Distributions // [private] handlePowerOverrideChanged
2769*c54f35caSApple OSS Distributions //*********************************************************************************
2770*c54f35caSApple OSS Distributions 
2771*c54f35caSApple OSS Distributions void
handlePowerOverrideChanged(IOPMRequest * request)2772*c54f35caSApple OSS Distributions IOService::handlePowerOverrideChanged( IOPMRequest * request )
2773*c54f35caSApple OSS Distributions {
2774*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
2775*c54f35caSApple OSS Distributions 	if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv) {
2776*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogOverrideOn, 0, 0);
2777*c54f35caSApple OSS Distributions 		fDeviceOverrideEnabled = true;
2778*c54f35caSApple OSS Distributions 	} else {
2779*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogOverrideOff, 0, 0);
2780*c54f35caSApple OSS Distributions 		fDeviceOverrideEnabled = false;
2781*c54f35caSApple OSS Distributions 	}
2782*c54f35caSApple OSS Distributions 
2783*c54f35caSApple OSS Distributions 	adjustPowerState();
2784*c54f35caSApple OSS Distributions }
2785*c54f35caSApple OSS Distributions 
2786*c54f35caSApple OSS Distributions //*********************************************************************************
2787*c54f35caSApple OSS Distributions // [private] computeDesiredState
2788*c54f35caSApple OSS Distributions //*********************************************************************************
2789*c54f35caSApple OSS Distributions 
2790*c54f35caSApple OSS Distributions void
computeDesiredState(unsigned long localClamp,bool computeOnly)2791*c54f35caSApple OSS Distributions IOService::computeDesiredState( unsigned long localClamp, bool computeOnly )
2792*c54f35caSApple OSS Distributions {
2793*c54f35caSApple OSS Distributions 	OSIterator *        iter;
2794*c54f35caSApple OSS Distributions 	OSObject *          next;
2795*c54f35caSApple OSS Distributions 	IOPowerConnection * connection;
2796*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex desiredState  = kPowerStateZero;
2797*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex newPowerState = kPowerStateZero;
2798*c54f35caSApple OSS Distributions 	bool                hasChildren   = false;
2799*c54f35caSApple OSS Distributions 
2800*c54f35caSApple OSS Distributions 	// Desired power state is always 0 without a controlling driver.
2801*c54f35caSApple OSS Distributions 
2802*c54f35caSApple OSS Distributions 	if (!fNumberOfPowerStates) {
2803*c54f35caSApple OSS Distributions 		fDesiredPowerState = kPowerStateZero;
2804*c54f35caSApple OSS Distributions 		return;
2805*c54f35caSApple OSS Distributions 	}
2806*c54f35caSApple OSS Distributions 
2807*c54f35caSApple OSS Distributions 	// Examine the children's desired power state.
2808*c54f35caSApple OSS Distributions 
2809*c54f35caSApple OSS Distributions 	iter = getChildIterator(gIOPowerPlane);
2810*c54f35caSApple OSS Distributions 	if (iter) {
2811*c54f35caSApple OSS Distributions 		while ((next = iter->getNextObject())) {
2812*c54f35caSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, next))) {
2813*c54f35caSApple OSS Distributions 				if (connection->getReadyFlag() == false) {
2814*c54f35caSApple OSS Distributions 					PM_LOG3("[%s] %s: connection not ready\n",
2815*c54f35caSApple OSS Distributions 					    getName(), __FUNCTION__);
2816*c54f35caSApple OSS Distributions 					continue;
2817*c54f35caSApple OSS Distributions 				}
2818*c54f35caSApple OSS Distributions 				if (connection->childHasRequestedPower()) {
2819*c54f35caSApple OSS Distributions 					hasChildren = true;
2820*c54f35caSApple OSS Distributions 				}
2821*c54f35caSApple OSS Distributions 				desiredState = StateMax(connection->getDesiredDomainState(), desiredState);
2822*c54f35caSApple OSS Distributions 			}
2823*c54f35caSApple OSS Distributions 		}
2824*c54f35caSApple OSS Distributions 		iter->release();
2825*c54f35caSApple OSS Distributions 	}
2826*c54f35caSApple OSS Distributions 	if (hasChildren) {
2827*c54f35caSApple OSS Distributions 		updatePowerClient(gIOPMPowerClientChildren, desiredState);
2828*c54f35caSApple OSS Distributions 	} else {
2829*c54f35caSApple OSS Distributions 		removePowerClient(gIOPMPowerClientChildren);
2830*c54f35caSApple OSS Distributions 	}
2831*c54f35caSApple OSS Distributions 
2832*c54f35caSApple OSS Distributions 	// Iterate through all power clients to determine the min power state.
2833*c54f35caSApple OSS Distributions 
2834*c54f35caSApple OSS Distributions 	iter = OSCollectionIterator::withCollection(fPowerClients);
2835*c54f35caSApple OSS Distributions 	if (iter) {
2836*c54f35caSApple OSS Distributions 		const OSSymbol * client;
2837*c54f35caSApple OSS Distributions 		while ((client = (const OSSymbol *) iter->getNextObject())) {
2838*c54f35caSApple OSS Distributions 			// Ignore child and driver when override is in effect.
2839*c54f35caSApple OSS Distributions 			if ((fDeviceOverrideEnabled ||
2840*c54f35caSApple OSS Distributions 			    (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)) &&
2841*c54f35caSApple OSS Distributions 			    ((client == gIOPMPowerClientChildren) ||
2842*c54f35caSApple OSS Distributions 			    (client == gIOPMPowerClientDriver))) {
2843*c54f35caSApple OSS Distributions 				continue;
2844*c54f35caSApple OSS Distributions 			}
2845*c54f35caSApple OSS Distributions 
2846*c54f35caSApple OSS Distributions 			// Ignore child proxy when children are present.
2847*c54f35caSApple OSS Distributions 			if (hasChildren && (client == gIOPMPowerClientChildProxy)) {
2848*c54f35caSApple OSS Distributions 				continue;
2849*c54f35caSApple OSS Distributions 			}
2850*c54f35caSApple OSS Distributions 
2851*c54f35caSApple OSS Distributions 			// Advisory tickles are irrelevant unless system is in full wake
2852*c54f35caSApple OSS Distributions 			if (client == gIOPMPowerClientAdvisoryTickle &&
2853*c54f35caSApple OSS Distributions 			    !gIOPMAdvisoryTickleEnabled) {
2854*c54f35caSApple OSS Distributions 				continue;
2855*c54f35caSApple OSS Distributions 			}
2856*c54f35caSApple OSS Distributions 
2857*c54f35caSApple OSS Distributions 			desiredState = getPowerStateForClient(client);
2858*c54f35caSApple OSS Distributions 			assert(desiredState < fNumberOfPowerStates);
2859*c54f35caSApple OSS Distributions 			PM_LOG1("  %u %s\n",
2860*c54f35caSApple OSS Distributions 			    (uint32_t) desiredState, client->getCStringNoCopy());
2861*c54f35caSApple OSS Distributions 
2862*c54f35caSApple OSS Distributions 			newPowerState = StateMax(newPowerState, desiredState);
2863*c54f35caSApple OSS Distributions 
2864*c54f35caSApple OSS Distributions 			if (client == gIOPMPowerClientDevice) {
2865*c54f35caSApple OSS Distributions 				fDeviceDesire = desiredState;
2866*c54f35caSApple OSS Distributions 			}
2867*c54f35caSApple OSS Distributions 		}
2868*c54f35caSApple OSS Distributions 		iter->release();
2869*c54f35caSApple OSS Distributions 	}
2870*c54f35caSApple OSS Distributions 
2871*c54f35caSApple OSS Distributions 	// Factor in the temporary power desires.
2872*c54f35caSApple OSS Distributions 
2873*c54f35caSApple OSS Distributions 	newPowerState = StateMax(newPowerState, localClamp);
2874*c54f35caSApple OSS Distributions 	newPowerState = StateMax(newPowerState, fTempClampPowerState);
2875*c54f35caSApple OSS Distributions 
2876*c54f35caSApple OSS Distributions 	// Limit check against max power override.
2877*c54f35caSApple OSS Distributions 
2878*c54f35caSApple OSS Distributions 	newPowerState = StateMin(newPowerState, fOverrideMaxPowerState);
2879*c54f35caSApple OSS Distributions 
2880*c54f35caSApple OSS Distributions 	// Limit check against number of power states.
2881*c54f35caSApple OSS Distributions 
2882*c54f35caSApple OSS Distributions 	if (newPowerState >= fNumberOfPowerStates) {
2883*c54f35caSApple OSS Distributions 		newPowerState = fHighestPowerState;
2884*c54f35caSApple OSS Distributions 	}
2885*c54f35caSApple OSS Distributions 
2886*c54f35caSApple OSS Distributions 	if (getPMRootDomain()->isAOTMode()) {
2887*c54f35caSApple OSS Distributions 		if ((kIOPMPreventIdleSleep & fPowerStates[newPowerState].capabilityFlags)
2888*c54f35caSApple OSS Distributions 		    && !(kIOPMPreventIdleSleep & fPowerStates[fDesiredPowerState].capabilityFlags)) {
2889*c54f35caSApple OSS Distributions 			getPMRootDomain()->claimSystemWakeEvent(this, kIOPMWakeEventAOTExit, getName(), NULL);
2890*c54f35caSApple OSS Distributions 		}
2891*c54f35caSApple OSS Distributions 	}
2892*c54f35caSApple OSS Distributions 
2893*c54f35caSApple OSS Distributions 	fDesiredPowerState = newPowerState;
2894*c54f35caSApple OSS Distributions 
2895*c54f35caSApple OSS Distributions 	PM_LOG1("  temp %u, clamp %u, current %u, new %u\n",
2896*c54f35caSApple OSS Distributions 	    (uint32_t) localClamp, (uint32_t) fTempClampPowerState,
2897*c54f35caSApple OSS Distributions 	    (uint32_t) fCurrentPowerState, (uint32_t) newPowerState);
2898*c54f35caSApple OSS Distributions 
2899*c54f35caSApple OSS Distributions 	if (!computeOnly) {
2900*c54f35caSApple OSS Distributions 		// Restart idle timer if possible when device desire has increased.
2901*c54f35caSApple OSS Distributions 		// Or if an advisory desire exists.
2902*c54f35caSApple OSS Distributions 
2903*c54f35caSApple OSS Distributions 		if (fIdleTimerPeriod && fIdleTimerStopped) {
2904*c54f35caSApple OSS Distributions 			restartIdleTimer();
2905*c54f35caSApple OSS Distributions 		}
2906*c54f35caSApple OSS Distributions 
2907*c54f35caSApple OSS Distributions 		// Invalidate cached tickle power state when desires change, and not
2908*c54f35caSApple OSS Distributions 		// due to a tickle request. In case the driver has requested a lower
2909*c54f35caSApple OSS Distributions 		// power state, but the tickle is caching a higher power state which
2910*c54f35caSApple OSS Distributions 		// will drop future tickles until the cached value is lowered or in-
2911*c54f35caSApple OSS Distributions 		// validated. The invalidation must occur before the power transition
2912*c54f35caSApple OSS Distributions 		// to avoid dropping a necessary tickle.
2913*c54f35caSApple OSS Distributions 
2914*c54f35caSApple OSS Distributions 		if ((getPMRequestType() != kIOPMRequestTypeActivityTickle) &&
2915*c54f35caSApple OSS Distributions 		    (fActivityTicklePowerState != kInvalidTicklePowerState)) {
2916*c54f35caSApple OSS Distributions 			IOLockLock(fActivityLock);
2917*c54f35caSApple OSS Distributions 			fActivityTicklePowerState = kInvalidTicklePowerState;
2918*c54f35caSApple OSS Distributions 			IOLockUnlock(fActivityLock);
2919*c54f35caSApple OSS Distributions 		}
2920*c54f35caSApple OSS Distributions 	}
2921*c54f35caSApple OSS Distributions }
2922*c54f35caSApple OSS Distributions 
2923*c54f35caSApple OSS Distributions //*********************************************************************************
2924*c54f35caSApple OSS Distributions // [public] currentPowerConsumption
2925*c54f35caSApple OSS Distributions //
2926*c54f35caSApple OSS Distributions //*********************************************************************************
2927*c54f35caSApple OSS Distributions 
2928*c54f35caSApple OSS Distributions unsigned long
currentPowerConsumption(void)2929*c54f35caSApple OSS Distributions IOService::currentPowerConsumption( void )
2930*c54f35caSApple OSS Distributions {
2931*c54f35caSApple OSS Distributions 	if (!initialized) {
2932*c54f35caSApple OSS Distributions 		return kIOPMUnknown;
2933*c54f35caSApple OSS Distributions 	}
2934*c54f35caSApple OSS Distributions 
2935*c54f35caSApple OSS Distributions 	return fCurrentPowerConsumption;
2936*c54f35caSApple OSS Distributions }
2937*c54f35caSApple OSS Distributions 
2938*c54f35caSApple OSS Distributions //*********************************************************************************
2939*c54f35caSApple OSS Distributions // [deprecated] getPMworkloop
2940*c54f35caSApple OSS Distributions //*********************************************************************************
2941*c54f35caSApple OSS Distributions 
2942*c54f35caSApple OSS Distributions #ifndef __LP64__
2943*c54f35caSApple OSS Distributions IOWorkLoop *
getPMworkloop(void)2944*c54f35caSApple OSS Distributions IOService::getPMworkloop( void )
2945*c54f35caSApple OSS Distributions {
2946*c54f35caSApple OSS Distributions 	return gIOPMWorkLoop;
2947*c54f35caSApple OSS Distributions }
2948*c54f35caSApple OSS Distributions #endif
2949*c54f35caSApple OSS Distributions 
2950*c54f35caSApple OSS Distributions #if NOT_YET
2951*c54f35caSApple OSS Distributions 
2952*c54f35caSApple OSS Distributions //*********************************************************************************
2953*c54f35caSApple OSS Distributions // Power Parent/Children Applier
2954*c54f35caSApple OSS Distributions //*********************************************************************************
2955*c54f35caSApple OSS Distributions 
2956*c54f35caSApple OSS Distributions static void
applyToPowerChildren(IOService * service,IOServiceApplierFunction applier,void * context,IOOptionBits options)2957*c54f35caSApple OSS Distributions applyToPowerChildren(
2958*c54f35caSApple OSS Distributions 	IOService *               service,
2959*c54f35caSApple OSS Distributions 	IOServiceApplierFunction  applier,
2960*c54f35caSApple OSS Distributions 	void *                    context,
2961*c54f35caSApple OSS Distributions 	IOOptionBits              options )
2962*c54f35caSApple OSS Distributions {
2963*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
2964*c54f35caSApple OSS Distributions 
2965*c54f35caSApple OSS Distributions 	IORegistryEntry *       entry;
2966*c54f35caSApple OSS Distributions 	IORegistryIterator *    iter;
2967*c54f35caSApple OSS Distributions 	IOPowerConnection *     connection;
2968*c54f35caSApple OSS Distributions 	IOService *             child;
2969*c54f35caSApple OSS Distributions 
2970*c54f35caSApple OSS Distributions 	iter = IORegistryIterator::iterateOver(service, gIOPowerPlane, options);
2971*c54f35caSApple OSS Distributions 	if (iter) {
2972*c54f35caSApple OSS Distributions 		while ((entry = iter->getNextObject())) {
2973*c54f35caSApple OSS Distributions 			// Get child of IOPowerConnection objects
2974*c54f35caSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, entry))) {
2975*c54f35caSApple OSS Distributions 				child = (IOService *) connection->copyChildEntry(gIOPowerPlane);
2976*c54f35caSApple OSS Distributions 				if (child) {
2977*c54f35caSApple OSS Distributions 					(*applier)(child, context);
2978*c54f35caSApple OSS Distributions 					child->release();
2979*c54f35caSApple OSS Distributions 				}
2980*c54f35caSApple OSS Distributions 			}
2981*c54f35caSApple OSS Distributions 		}
2982*c54f35caSApple OSS Distributions 		iter->release();
2983*c54f35caSApple OSS Distributions 	}
2984*c54f35caSApple OSS Distributions }
2985*c54f35caSApple OSS Distributions 
2986*c54f35caSApple OSS Distributions static void
applyToPowerParent(IOService * service,IOServiceApplierFunction applier,void * context,IOOptionBits options)2987*c54f35caSApple OSS Distributions applyToPowerParent(
2988*c54f35caSApple OSS Distributions 	IOService *               service,
2989*c54f35caSApple OSS Distributions 	IOServiceApplierFunction  applier,
2990*c54f35caSApple OSS Distributions 	void *                    context,
2991*c54f35caSApple OSS Distributions 	IOOptionBits              options )
2992*c54f35caSApple OSS Distributions {
2993*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
2994*c54f35caSApple OSS Distributions 
2995*c54f35caSApple OSS Distributions 	IORegistryEntry *       entry;
2996*c54f35caSApple OSS Distributions 	IORegistryIterator *    iter;
2997*c54f35caSApple OSS Distributions 	IOPowerConnection *     connection;
2998*c54f35caSApple OSS Distributions 	IOService *             parent;
2999*c54f35caSApple OSS Distributions 
3000*c54f35caSApple OSS Distributions 	iter = IORegistryIterator::iterateOver(service, gIOPowerPlane,
3001*c54f35caSApple OSS Distributions 	    options | kIORegistryIterateParents);
3002*c54f35caSApple OSS Distributions 	if (iter) {
3003*c54f35caSApple OSS Distributions 		while ((entry = iter->getNextObject())) {
3004*c54f35caSApple OSS Distributions 			// Get child of IOPowerConnection objects
3005*c54f35caSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, entry))) {
3006*c54f35caSApple OSS Distributions 				parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
3007*c54f35caSApple OSS Distributions 				if (parent) {
3008*c54f35caSApple OSS Distributions 					(*applier)(parent, context);
3009*c54f35caSApple OSS Distributions 					parent->release();
3010*c54f35caSApple OSS Distributions 				}
3011*c54f35caSApple OSS Distributions 			}
3012*c54f35caSApple OSS Distributions 		}
3013*c54f35caSApple OSS Distributions 		iter->release();
3014*c54f35caSApple OSS Distributions 	}
3015*c54f35caSApple OSS Distributions }
3016*c54f35caSApple OSS Distributions 
3017*c54f35caSApple OSS Distributions #endif /* NOT_YET */
3018*c54f35caSApple OSS Distributions 
3019*c54f35caSApple OSS Distributions // MARK: -
3020*c54f35caSApple OSS Distributions // MARK: Activity Tickle & Idle Timer
3021*c54f35caSApple OSS Distributions 
3022*c54f35caSApple OSS Distributions void
setAdvisoryTickleEnable(bool enable)3023*c54f35caSApple OSS Distributions IOService::setAdvisoryTickleEnable( bool enable )
3024*c54f35caSApple OSS Distributions {
3025*c54f35caSApple OSS Distributions 	gIOPMAdvisoryTickleEnabled = enable;
3026*c54f35caSApple OSS Distributions }
3027*c54f35caSApple OSS Distributions 
3028*c54f35caSApple OSS Distributions //*********************************************************************************
3029*c54f35caSApple OSS Distributions // [public] activityTickle
3030*c54f35caSApple OSS Distributions //
3031*c54f35caSApple OSS Distributions // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
3032*c54f35caSApple OSS Distributions // flag to be set, and the device state checked.  If the device has been
3033*c54f35caSApple OSS Distributions // powered down, it is powered up again.
3034*c54f35caSApple OSS Distributions // The tickle with parameter kIOPMSubclassPolicy is ignored here and
3035*c54f35caSApple OSS Distributions // should be intercepted by a subclass.
3036*c54f35caSApple OSS Distributions //*********************************************************************************
3037*c54f35caSApple OSS Distributions 
3038*c54f35caSApple OSS Distributions bool
activityTickle(unsigned long type,unsigned long stateNumber)3039*c54f35caSApple OSS Distributions IOService::activityTickle( unsigned long type, unsigned long stateNumber )
3040*c54f35caSApple OSS Distributions {
3041*c54f35caSApple OSS Distributions 	if (!initialized) {
3042*c54f35caSApple OSS Distributions 		return true; // no power change
3043*c54f35caSApple OSS Distributions 	}
3044*c54f35caSApple OSS Distributions 
3045*c54f35caSApple OSS Distributions 	if (!fPowerStates) {
3046*c54f35caSApple OSS Distributions 		// registerPowerDriver may not have completed
3047*c54f35caSApple OSS Distributions 		IOPMRequest *   request;
3048*c54f35caSApple OSS Distributions 
3049*c54f35caSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeDeferredActivityTickle );
3050*c54f35caSApple OSS Distributions 		if (request) {
3051*c54f35caSApple OSS Distributions 			request->fArg0 = (void *)            type;
3052*c54f35caSApple OSS Distributions 			request->fArg1 = (void *)(uintptr_t) stateNumber;
3053*c54f35caSApple OSS Distributions 			submitPMRequest(request);
3054*c54f35caSApple OSS Distributions 		}
3055*c54f35caSApple OSS Distributions 		// Returns false if the activityTickle might cause a transition to a
3056*c54f35caSApple OSS Distributions 		// higher powered state. We don't know, so this seems safest.
3057*c54f35caSApple OSS Distributions 		return false;
3058*c54f35caSApple OSS Distributions 	}
3059*c54f35caSApple OSS Distributions 
3060*c54f35caSApple OSS Distributions 	return _activityTickle(type, stateNumber);
3061*c54f35caSApple OSS Distributions }
3062*c54f35caSApple OSS Distributions 
3063*c54f35caSApple OSS Distributions //*********************************************************************************
3064*c54f35caSApple OSS Distributions // [private] handleDeferredActivityTickle
3065*c54f35caSApple OSS Distributions //*********************************************************************************
3066*c54f35caSApple OSS Distributions 
3067*c54f35caSApple OSS Distributions void
handleDeferredActivityTickle(IOPMRequest * request)3068*c54f35caSApple OSS Distributions IOService::handleDeferredActivityTickle( IOPMRequest * request )
3069*c54f35caSApple OSS Distributions {
3070*c54f35caSApple OSS Distributions 	unsigned long type        = (unsigned long) request->fArg1;
3071*c54f35caSApple OSS Distributions 	unsigned long stateNumber = (unsigned long) request->fArg2;
3072*c54f35caSApple OSS Distributions 
3073*c54f35caSApple OSS Distributions 	if (!fPowerStates) {
3074*c54f35caSApple OSS Distributions 		// registerPowerDriver was not called before activityTickle()
3075*c54f35caSApple OSS Distributions 		return;
3076*c54f35caSApple OSS Distributions 	}
3077*c54f35caSApple OSS Distributions 	(void) _activityTickle(type, stateNumber);
3078*c54f35caSApple OSS Distributions }
3079*c54f35caSApple OSS Distributions 
3080*c54f35caSApple OSS Distributions //*********************************************************************************
3081*c54f35caSApple OSS Distributions // [private] _activityTickle
3082*c54f35caSApple OSS Distributions //
3083*c54f35caSApple OSS Distributions // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
3084*c54f35caSApple OSS Distributions // flag to be set, and the device state checked.  If the device has been
3085*c54f35caSApple OSS Distributions // powered down, it is powered up again.
3086*c54f35caSApple OSS Distributions // The tickle with parameter kIOPMSubclassPolicy is ignored here and
3087*c54f35caSApple OSS Distributions // should be intercepted by a subclass.
3088*c54f35caSApple OSS Distributions //*********************************************************************************
3089*c54f35caSApple OSS Distributions 
3090*c54f35caSApple OSS Distributions bool
_activityTickle(unsigned long type,unsigned long stateNumber)3091*c54f35caSApple OSS Distributions IOService::_activityTickle( unsigned long type, unsigned long stateNumber )
3092*c54f35caSApple OSS Distributions {
3093*c54f35caSApple OSS Distributions 	IOPMRequest *   request;
3094*c54f35caSApple OSS Distributions 	bool            noPowerChange = true;
3095*c54f35caSApple OSS Distributions 	uint32_t        tickleFlags;
3096*c54f35caSApple OSS Distributions 
3097*c54f35caSApple OSS Distributions 	if ((type == kIOPMSuperclassPolicy1) && StateOrder(stateNumber)) {
3098*c54f35caSApple OSS Distributions 		IOLockLock(fActivityLock);
3099*c54f35caSApple OSS Distributions 
3100*c54f35caSApple OSS Distributions 		// Record device activity for the idle timer handler.
3101*c54f35caSApple OSS Distributions 
3102*c54f35caSApple OSS Distributions 		fDeviceWasActive = true;
3103*c54f35caSApple OSS Distributions 		fActivityTickleCount++;
3104*c54f35caSApple OSS Distributions 		clock_get_uptime(&fDeviceActiveTimestamp);
3105*c54f35caSApple OSS Distributions 
3106*c54f35caSApple OSS Distributions 		PM_ACTION_TICKLE(actionActivityTickle);
3107*c54f35caSApple OSS Distributions 
3108*c54f35caSApple OSS Distributions 		// Record the last tickle power state.
3109*c54f35caSApple OSS Distributions 		// This helps to filter out redundant tickles as
3110*c54f35caSApple OSS Distributions 		// this function may be called from the data path.
3111*c54f35caSApple OSS Distributions 
3112*c54f35caSApple OSS Distributions 		if ((fActivityTicklePowerState == kInvalidTicklePowerState)
3113*c54f35caSApple OSS Distributions 		    || StateOrder(fActivityTicklePowerState) < StateOrder(stateNumber)) {
3114*c54f35caSApple OSS Distributions 			fActivityTicklePowerState = stateNumber;
3115*c54f35caSApple OSS Distributions 			noPowerChange = false;
3116*c54f35caSApple OSS Distributions 
3117*c54f35caSApple OSS Distributions 			tickleFlags = kTickleTypeActivity | kTickleTypePowerRise;
3118*c54f35caSApple OSS Distributions 			request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3119*c54f35caSApple OSS Distributions 			if (request) {
3120*c54f35caSApple OSS Distributions 				request->fArg0 = (void *)            stateNumber;
3121*c54f35caSApple OSS Distributions 				request->fArg1 = (void *)(uintptr_t) tickleFlags;
3122*c54f35caSApple OSS Distributions 				request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3123*c54f35caSApple OSS Distributions 				submitPMRequest(request);
3124*c54f35caSApple OSS Distributions 			}
3125*c54f35caSApple OSS Distributions 		}
3126*c54f35caSApple OSS Distributions 
3127*c54f35caSApple OSS Distributions 		IOLockUnlock(fActivityLock);
3128*c54f35caSApple OSS Distributions 	} else if ((type == kIOPMActivityTickleTypeAdvisory) &&
3129*c54f35caSApple OSS Distributions 	    ((stateNumber = fDeviceUsablePowerState) != kPowerStateZero)) {
3130*c54f35caSApple OSS Distributions 		IOLockLock(fActivityLock);
3131*c54f35caSApple OSS Distributions 
3132*c54f35caSApple OSS Distributions 		fAdvisoryTickled = true;
3133*c54f35caSApple OSS Distributions 
3134*c54f35caSApple OSS Distributions 		if (fAdvisoryTicklePowerState != stateNumber) {
3135*c54f35caSApple OSS Distributions 			fAdvisoryTicklePowerState = stateNumber;
3136*c54f35caSApple OSS Distributions 			noPowerChange = false;
3137*c54f35caSApple OSS Distributions 
3138*c54f35caSApple OSS Distributions 			tickleFlags = kTickleTypeAdvisory | kTickleTypePowerRise;
3139*c54f35caSApple OSS Distributions 			request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3140*c54f35caSApple OSS Distributions 			if (request) {
3141*c54f35caSApple OSS Distributions 				request->fArg0 = (void *)            stateNumber;
3142*c54f35caSApple OSS Distributions 				request->fArg1 = (void *)(uintptr_t) tickleFlags;
3143*c54f35caSApple OSS Distributions 				request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3144*c54f35caSApple OSS Distributions 				submitPMRequest(request);
3145*c54f35caSApple OSS Distributions 			}
3146*c54f35caSApple OSS Distributions 		}
3147*c54f35caSApple OSS Distributions 
3148*c54f35caSApple OSS Distributions 		IOLockUnlock(fActivityLock);
3149*c54f35caSApple OSS Distributions 	}
3150*c54f35caSApple OSS Distributions 
3151*c54f35caSApple OSS Distributions 	// Returns false if the activityTickle might cause a transition to a
3152*c54f35caSApple OSS Distributions 	// higher powered state, true otherwise.
3153*c54f35caSApple OSS Distributions 
3154*c54f35caSApple OSS Distributions 	return noPowerChange;
3155*c54f35caSApple OSS Distributions }
3156*c54f35caSApple OSS Distributions 
3157*c54f35caSApple OSS Distributions //*********************************************************************************
3158*c54f35caSApple OSS Distributions // [private] handleActivityTickle
3159*c54f35caSApple OSS Distributions //*********************************************************************************
3160*c54f35caSApple OSS Distributions 
3161*c54f35caSApple OSS Distributions void
handleActivityTickle(IOPMRequest * request)3162*c54f35caSApple OSS Distributions IOService::handleActivityTickle( IOPMRequest * request )
3163*c54f35caSApple OSS Distributions {
3164*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex ticklePowerState = (IOPMPowerStateIndex) request->fArg0;
3165*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex tickleFlags      = (IOPMPowerStateIndex) request->fArg1;
3166*c54f35caSApple OSS Distributions 	uint32_t            tickleGeneration = (uint32_t)(uintptr_t) request->fArg2;
3167*c54f35caSApple OSS Distributions 	bool adjustPower = false;
3168*c54f35caSApple OSS Distributions 
3169*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
3170*c54f35caSApple OSS Distributions 	if (fResetPowerStateOnWake && (tickleGeneration != gIOPMTickleGeneration)) {
3171*c54f35caSApple OSS Distributions 		// Drivers that don't want power restored on wake will drop any
3172*c54f35caSApple OSS Distributions 		// tickles that pre-dates the current system wake. The model is
3173*c54f35caSApple OSS Distributions 		// that each wake is a fresh start, with power state depressed
3174*c54f35caSApple OSS Distributions 		// until a new tickle or an explicit power up request from the
3175*c54f35caSApple OSS Distributions 		// driver. It is possible for the PM work loop to enter the
3176*c54f35caSApple OSS Distributions 		// system sleep path with tickle requests queued.
3177*c54f35caSApple OSS Distributions 
3178*c54f35caSApple OSS Distributions 		return;
3179*c54f35caSApple OSS Distributions 	}
3180*c54f35caSApple OSS Distributions 
3181*c54f35caSApple OSS Distributions 	if (tickleFlags & kTickleTypeActivity) {
3182*c54f35caSApple OSS Distributions 		IOPMPowerStateIndex deviceDesireOrder = StateOrder(fDeviceDesire);
3183*c54f35caSApple OSS Distributions 		IOPMPowerStateIndex idleTimerGeneration = ticklePowerState; // kTickleTypePowerDrop
3184*c54f35caSApple OSS Distributions 
3185*c54f35caSApple OSS Distributions 		if (tickleFlags & kTickleTypePowerRise) {
3186*c54f35caSApple OSS Distributions 			if ((StateOrder(ticklePowerState) > deviceDesireOrder) &&
3187*c54f35caSApple OSS Distributions 			    (ticklePowerState < fNumberOfPowerStates)) {
3188*c54f35caSApple OSS Distributions 				fIdleTimerMinPowerState = ticklePowerState;
3189*c54f35caSApple OSS Distributions 				updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
3190*c54f35caSApple OSS Distributions 				adjustPower = true;
3191*c54f35caSApple OSS Distributions 			}
3192*c54f35caSApple OSS Distributions 		} else if ((deviceDesireOrder > StateOrder(fIdleTimerMinPowerState)) &&
3193*c54f35caSApple OSS Distributions 		    (idleTimerGeneration == fIdleTimerGeneration)) {
3194*c54f35caSApple OSS Distributions 			// Power drop due to idle timer expiration.
3195*c54f35caSApple OSS Distributions 			// Do not allow idle timer to reduce power below tickle power.
3196*c54f35caSApple OSS Distributions 			// This prevents the idle timer from decreasing the device desire
3197*c54f35caSApple OSS Distributions 			// to zero and cancelling the effect of a pre-sleep tickle when
3198*c54f35caSApple OSS Distributions 			// system wakes up to doze state, while the device is unable to
3199*c54f35caSApple OSS Distributions 			// raise its power state to satisfy the tickle.
3200*c54f35caSApple OSS Distributions 
3201*c54f35caSApple OSS Distributions 			deviceDesireOrder--;
3202*c54f35caSApple OSS Distributions 			if (deviceDesireOrder < fNumberOfPowerStates) {
3203*c54f35caSApple OSS Distributions 				ticklePowerState = fPowerStates[deviceDesireOrder].stateOrderToIndex;
3204*c54f35caSApple OSS Distributions 				updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
3205*c54f35caSApple OSS Distributions 				adjustPower = true;
3206*c54f35caSApple OSS Distributions 			}
3207*c54f35caSApple OSS Distributions 		}
3208*c54f35caSApple OSS Distributions 	} else { // advisory tickle
3209*c54f35caSApple OSS Distributions 		if (tickleFlags & kTickleTypePowerRise) {
3210*c54f35caSApple OSS Distributions 			if ((ticklePowerState == fDeviceUsablePowerState) &&
3211*c54f35caSApple OSS Distributions 			    (ticklePowerState < fNumberOfPowerStates)) {
3212*c54f35caSApple OSS Distributions 				updatePowerClient(gIOPMPowerClientAdvisoryTickle, ticklePowerState);
3213*c54f35caSApple OSS Distributions 				fHasAdvisoryDesire = true;
3214*c54f35caSApple OSS Distributions 				fAdvisoryTickleUsed = true;
3215*c54f35caSApple OSS Distributions 				adjustPower = true;
3216*c54f35caSApple OSS Distributions 			} else {
3217*c54f35caSApple OSS Distributions 				IOLockLock(fActivityLock);
3218*c54f35caSApple OSS Distributions 				fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3219*c54f35caSApple OSS Distributions 				IOLockUnlock(fActivityLock);
3220*c54f35caSApple OSS Distributions 			}
3221*c54f35caSApple OSS Distributions 		} else if (fHasAdvisoryDesire) {
3222*c54f35caSApple OSS Distributions 			removePowerClient(gIOPMPowerClientAdvisoryTickle);
3223*c54f35caSApple OSS Distributions 			fHasAdvisoryDesire = false;
3224*c54f35caSApple OSS Distributions 			adjustPower = true;
3225*c54f35caSApple OSS Distributions 		}
3226*c54f35caSApple OSS Distributions 	}
3227*c54f35caSApple OSS Distributions 
3228*c54f35caSApple OSS Distributions 	if (adjustPower) {
3229*c54f35caSApple OSS Distributions 		adjustPowerState();
3230*c54f35caSApple OSS Distributions 	}
3231*c54f35caSApple OSS Distributions }
3232*c54f35caSApple OSS Distributions 
3233*c54f35caSApple OSS Distributions //******************************************************************************
3234*c54f35caSApple OSS Distributions // [public] setIdleTimerPeriod
3235*c54f35caSApple OSS Distributions //
3236*c54f35caSApple OSS Distributions // A subclass policy-maker is using our standard idleness detection service.
3237*c54f35caSApple OSS Distributions // Start the idle timer. Period is in seconds.
3238*c54f35caSApple OSS Distributions //******************************************************************************
3239*c54f35caSApple OSS Distributions 
3240*c54f35caSApple OSS Distributions IOReturn
setIdleTimerPeriod(unsigned long period)3241*c54f35caSApple OSS Distributions IOService::setIdleTimerPeriod( unsigned long period )
3242*c54f35caSApple OSS Distributions {
3243*c54f35caSApple OSS Distributions 	if (!initialized) {
3244*c54f35caSApple OSS Distributions 		return IOPMNotYetInitialized;
3245*c54f35caSApple OSS Distributions 	}
3246*c54f35caSApple OSS Distributions 
3247*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogSetIdleTimerPeriod, period, fIdleTimerPeriod);
3248*c54f35caSApple OSS Distributions 
3249*c54f35caSApple OSS Distributions 	if (period > INT_MAX) {
3250*c54f35caSApple OSS Distributions 		return kIOReturnBadArgument;
3251*c54f35caSApple OSS Distributions 	}
3252*c54f35caSApple OSS Distributions 
3253*c54f35caSApple OSS Distributions 	IOPMRequest * request =
3254*c54f35caSApple OSS Distributions 	    acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod );
3255*c54f35caSApple OSS Distributions 	if (!request) {
3256*c54f35caSApple OSS Distributions 		return kIOReturnNoMemory;
3257*c54f35caSApple OSS Distributions 	}
3258*c54f35caSApple OSS Distributions 
3259*c54f35caSApple OSS Distributions 	request->fArg0 = (void *) period;
3260*c54f35caSApple OSS Distributions 	submitPMRequest( request );
3261*c54f35caSApple OSS Distributions 
3262*c54f35caSApple OSS Distributions 	return kIOReturnSuccess;
3263*c54f35caSApple OSS Distributions }
3264*c54f35caSApple OSS Distributions 
3265*c54f35caSApple OSS Distributions IOReturn
setIgnoreIdleTimer(bool ignore)3266*c54f35caSApple OSS Distributions IOService::setIgnoreIdleTimer( bool ignore )
3267*c54f35caSApple OSS Distributions {
3268*c54f35caSApple OSS Distributions 	if (!initialized) {
3269*c54f35caSApple OSS Distributions 		return IOPMNotYetInitialized;
3270*c54f35caSApple OSS Distributions 	}
3271*c54f35caSApple OSS Distributions 
3272*c54f35caSApple OSS Distributions 	OUR_PMLog(kIOPMRequestTypeIgnoreIdleTimer, ignore, 0);
3273*c54f35caSApple OSS Distributions 
3274*c54f35caSApple OSS Distributions 	IOPMRequest * request =
3275*c54f35caSApple OSS Distributions 	    acquirePMRequest( this, kIOPMRequestTypeIgnoreIdleTimer );
3276*c54f35caSApple OSS Distributions 	if (!request) {
3277*c54f35caSApple OSS Distributions 		return kIOReturnNoMemory;
3278*c54f35caSApple OSS Distributions 	}
3279*c54f35caSApple OSS Distributions 
3280*c54f35caSApple OSS Distributions 	request->fArg0 = (void *) ignore;
3281*c54f35caSApple OSS Distributions 	submitPMRequest( request );
3282*c54f35caSApple OSS Distributions 
3283*c54f35caSApple OSS Distributions 	return kIOReturnSuccess;
3284*c54f35caSApple OSS Distributions }
3285*c54f35caSApple OSS Distributions 
3286*c54f35caSApple OSS Distributions //******************************************************************************
3287*c54f35caSApple OSS Distributions // [public] nextIdleTimeout
3288*c54f35caSApple OSS Distributions //
3289*c54f35caSApple OSS Distributions // Returns how many "seconds from now" the device should idle into its
3290*c54f35caSApple OSS Distributions // next lowest power state.
3291*c54f35caSApple OSS Distributions //******************************************************************************
3292*c54f35caSApple OSS Distributions 
3293*c54f35caSApple OSS Distributions SInt32
nextIdleTimeout(AbsoluteTime currentTime,AbsoluteTime lastActivity,unsigned int powerState)3294*c54f35caSApple OSS Distributions IOService::nextIdleTimeout(
3295*c54f35caSApple OSS Distributions 	AbsoluteTime currentTime,
3296*c54f35caSApple OSS Distributions 	AbsoluteTime lastActivity,
3297*c54f35caSApple OSS Distributions 	unsigned int powerState)
3298*c54f35caSApple OSS Distributions {
3299*c54f35caSApple OSS Distributions 	AbsoluteTime        delta;
3300*c54f35caSApple OSS Distributions 	UInt64              delta_ns;
3301*c54f35caSApple OSS Distributions 	SInt32              delta_secs;
3302*c54f35caSApple OSS Distributions 	SInt32              delay_secs;
3303*c54f35caSApple OSS Distributions 
3304*c54f35caSApple OSS Distributions 	// Calculate time difference using funky macro from clock.h.
3305*c54f35caSApple OSS Distributions 	delta = currentTime;
3306*c54f35caSApple OSS Distributions 	SUB_ABSOLUTETIME(&delta, &lastActivity);
3307*c54f35caSApple OSS Distributions 
3308*c54f35caSApple OSS Distributions 	// Figure it in seconds.
3309*c54f35caSApple OSS Distributions 	absolutetime_to_nanoseconds(delta, &delta_ns);
3310*c54f35caSApple OSS Distributions 	delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
3311*c54f35caSApple OSS Distributions 
3312*c54f35caSApple OSS Distributions 	// Be paranoid about delta somehow exceeding timer period.
3313*c54f35caSApple OSS Distributions 	if (delta_secs < (int) fIdleTimerPeriod) {
3314*c54f35caSApple OSS Distributions 		delay_secs = (int) fIdleTimerPeriod - delta_secs;
3315*c54f35caSApple OSS Distributions 	} else {
3316*c54f35caSApple OSS Distributions 		delay_secs = (int) fIdleTimerPeriod;
3317*c54f35caSApple OSS Distributions 	}
3318*c54f35caSApple OSS Distributions 
3319*c54f35caSApple OSS Distributions 	return (SInt32)delay_secs;
3320*c54f35caSApple OSS Distributions }
3321*c54f35caSApple OSS Distributions 
3322*c54f35caSApple OSS Distributions //*********************************************************************************
3323*c54f35caSApple OSS Distributions // [public] start_PM_idle_timer
3324*c54f35caSApple OSS Distributions //*********************************************************************************
3325*c54f35caSApple OSS Distributions 
3326*c54f35caSApple OSS Distributions void
start_PM_idle_timer(void)3327*c54f35caSApple OSS Distributions IOService::start_PM_idle_timer( void )
3328*c54f35caSApple OSS Distributions {
3329*c54f35caSApple OSS Distributions 	static const int    maxTimeout = 100000;
3330*c54f35caSApple OSS Distributions 	static const int    minTimeout = 1;
3331*c54f35caSApple OSS Distributions 	AbsoluteTime        uptime, deadline;
3332*c54f35caSApple OSS Distributions 	SInt32              idle_in = 0;
3333*c54f35caSApple OSS Distributions 	boolean_t           pending;
3334*c54f35caSApple OSS Distributions 
3335*c54f35caSApple OSS Distributions 	if (!initialized || !fIdleTimerPeriod ||
3336*c54f35caSApple OSS Distributions 	    ((unsigned int) fCurrentPowerState != fCurrentPowerState)) {
3337*c54f35caSApple OSS Distributions 		return;
3338*c54f35caSApple OSS Distributions 	}
3339*c54f35caSApple OSS Distributions 
3340*c54f35caSApple OSS Distributions 	IOLockLock(fActivityLock);
3341*c54f35caSApple OSS Distributions 
3342*c54f35caSApple OSS Distributions 	clock_get_uptime(&uptime);
3343*c54f35caSApple OSS Distributions 
3344*c54f35caSApple OSS Distributions 	// Subclasses may modify idle sleep algorithm
3345*c54f35caSApple OSS Distributions 	idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, (unsigned int) fCurrentPowerState);
3346*c54f35caSApple OSS Distributions 
3347*c54f35caSApple OSS Distributions 	// Check for out-of range responses
3348*c54f35caSApple OSS Distributions 	if (idle_in > maxTimeout) {
3349*c54f35caSApple OSS Distributions 		// use standard implementation
3350*c54f35caSApple OSS Distributions 		idle_in = IOService::nextIdleTimeout(uptime,
3351*c54f35caSApple OSS Distributions 		    fDeviceActiveTimestamp,
3352*c54f35caSApple OSS Distributions 		    (unsigned int) fCurrentPowerState);
3353*c54f35caSApple OSS Distributions 	} else if (idle_in < minTimeout) {
3354*c54f35caSApple OSS Distributions 		idle_in = fIdleTimerPeriod;
3355*c54f35caSApple OSS Distributions 	}
3356*c54f35caSApple OSS Distributions 
3357*c54f35caSApple OSS Distributions 	IOLockUnlock(fActivityLock);
3358*c54f35caSApple OSS Distributions 
3359*c54f35caSApple OSS Distributions 	fNextIdleTimerPeriod = idle_in;
3360*c54f35caSApple OSS Distributions 	fIdleTimerStartTime = uptime;
3361*c54f35caSApple OSS Distributions 
3362*c54f35caSApple OSS Distributions 	retain();
3363*c54f35caSApple OSS Distributions 	clock_interval_to_absolutetime_interval(idle_in, kSecondScale, &deadline);
3364*c54f35caSApple OSS Distributions 	ADD_ABSOLUTETIME(&deadline, &uptime);
3365*c54f35caSApple OSS Distributions 	pending = thread_call_enter_delayed(fIdleTimer, deadline);
3366*c54f35caSApple OSS Distributions 	if (pending) {
3367*c54f35caSApple OSS Distributions 		release();
3368*c54f35caSApple OSS Distributions 	}
3369*c54f35caSApple OSS Distributions }
3370*c54f35caSApple OSS Distributions 
3371*c54f35caSApple OSS Distributions //*********************************************************************************
3372*c54f35caSApple OSS Distributions // [private] restartIdleTimer
3373*c54f35caSApple OSS Distributions //*********************************************************************************
3374*c54f35caSApple OSS Distributions 
3375*c54f35caSApple OSS Distributions void
restartIdleTimer(void)3376*c54f35caSApple OSS Distributions IOService::restartIdleTimer( void )
3377*c54f35caSApple OSS Distributions {
3378*c54f35caSApple OSS Distributions 	if (fDeviceDesire != kPowerStateZero) {
3379*c54f35caSApple OSS Distributions 		fIdleTimerStopped = false;
3380*c54f35caSApple OSS Distributions 		fActivityTickleCount = 0;
3381*c54f35caSApple OSS Distributions 		start_PM_idle_timer();
3382*c54f35caSApple OSS Distributions 	} else if (fHasAdvisoryDesire) {
3383*c54f35caSApple OSS Distributions 		fIdleTimerStopped = false;
3384*c54f35caSApple OSS Distributions 		start_PM_idle_timer();
3385*c54f35caSApple OSS Distributions 	} else {
3386*c54f35caSApple OSS Distributions 		fIdleTimerStopped = true;
3387*c54f35caSApple OSS Distributions 	}
3388*c54f35caSApple OSS Distributions }
3389*c54f35caSApple OSS Distributions 
3390*c54f35caSApple OSS Distributions //*********************************************************************************
3391*c54f35caSApple OSS Distributions // idle_timer_expired
3392*c54f35caSApple OSS Distributions //*********************************************************************************
3393*c54f35caSApple OSS Distributions 
3394*c54f35caSApple OSS Distributions static void
idle_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)3395*c54f35caSApple OSS Distributions idle_timer_expired(
3396*c54f35caSApple OSS Distributions 	thread_call_param_t arg0, thread_call_param_t arg1 )
3397*c54f35caSApple OSS Distributions {
3398*c54f35caSApple OSS Distributions 	IOService * me = (IOService *) arg0;
3399*c54f35caSApple OSS Distributions 
3400*c54f35caSApple OSS Distributions 	if (gIOPMWorkLoop) {
3401*c54f35caSApple OSS Distributions 		gIOPMWorkLoop->runAction(
3402*c54f35caSApple OSS Distributions 			OSMemberFunctionCast(IOWorkLoop::Action, me,
3403*c54f35caSApple OSS Distributions 			&IOService::idleTimerExpired),
3404*c54f35caSApple OSS Distributions 			me);
3405*c54f35caSApple OSS Distributions 	}
3406*c54f35caSApple OSS Distributions 
3407*c54f35caSApple OSS Distributions 	me->release();
3408*c54f35caSApple OSS Distributions }
3409*c54f35caSApple OSS Distributions 
3410*c54f35caSApple OSS Distributions //*********************************************************************************
3411*c54f35caSApple OSS Distributions // [private] idleTimerExpired
3412*c54f35caSApple OSS Distributions //
3413*c54f35caSApple OSS Distributions // The idle timer has expired. If there has been activity since the last
3414*c54f35caSApple OSS Distributions // expiration, just restart the timer and return.  If there has not been
3415*c54f35caSApple OSS Distributions // activity, switch to the next lower power state and restart the timer.
3416*c54f35caSApple OSS Distributions //*********************************************************************************
3417*c54f35caSApple OSS Distributions 
3418*c54f35caSApple OSS Distributions void
idleTimerExpired(void)3419*c54f35caSApple OSS Distributions IOService::idleTimerExpired( void )
3420*c54f35caSApple OSS Distributions {
3421*c54f35caSApple OSS Distributions 	IOPMRequest *   request;
3422*c54f35caSApple OSS Distributions 	bool            restartTimer = true;
3423*c54f35caSApple OSS Distributions 	uint32_t        tickleFlags;
3424*c54f35caSApple OSS Distributions 
3425*c54f35caSApple OSS Distributions 	if (!initialized || !fIdleTimerPeriod || fIdleTimerStopped ||
3426*c54f35caSApple OSS Distributions 	    fLockedFlags.PMStop) {
3427*c54f35caSApple OSS Distributions 		return;
3428*c54f35caSApple OSS Distributions 	}
3429*c54f35caSApple OSS Distributions 
3430*c54f35caSApple OSS Distributions 	fIdleTimerStartTime = 0;
3431*c54f35caSApple OSS Distributions 
3432*c54f35caSApple OSS Distributions 	IOLockLock(fActivityLock);
3433*c54f35caSApple OSS Distributions 
3434*c54f35caSApple OSS Distributions 	// Check for device activity (tickles) over last timer period.
3435*c54f35caSApple OSS Distributions 
3436*c54f35caSApple OSS Distributions 	if (fDeviceWasActive) {
3437*c54f35caSApple OSS Distributions 		// Device was active - do not drop power, restart timer.
3438*c54f35caSApple OSS Distributions 		fDeviceWasActive = false;
3439*c54f35caSApple OSS Distributions 	} else if (!fIdleTimerIgnored) {
3440*c54f35caSApple OSS Distributions 		// No device activity - drop power state by one level.
3441*c54f35caSApple OSS Distributions 		// Decrement the cached tickle power state when possible.
3442*c54f35caSApple OSS Distributions 		// This value may be kInvalidTicklePowerState before activityTickle()
3443*c54f35caSApple OSS Distributions 		// is called, but the power drop request must be issued regardless.
3444*c54f35caSApple OSS Distributions 
3445*c54f35caSApple OSS Distributions 		if ((fActivityTicklePowerState != kInvalidTicklePowerState) &&
3446*c54f35caSApple OSS Distributions 		    (fActivityTicklePowerState != kPowerStateZero)) {
3447*c54f35caSApple OSS Distributions 			fActivityTicklePowerState--;
3448*c54f35caSApple OSS Distributions 		}
3449*c54f35caSApple OSS Distributions 
3450*c54f35caSApple OSS Distributions 		tickleFlags = kTickleTypeActivity | kTickleTypePowerDrop;
3451*c54f35caSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3452*c54f35caSApple OSS Distributions 		if (request) {
3453*c54f35caSApple OSS Distributions 			request->fArg0 = (void *)(uintptr_t) fIdleTimerGeneration;
3454*c54f35caSApple OSS Distributions 			request->fArg1 = (void *)(uintptr_t) tickleFlags;
3455*c54f35caSApple OSS Distributions 			request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3456*c54f35caSApple OSS Distributions 			submitPMRequest( request );
3457*c54f35caSApple OSS Distributions 
3458*c54f35caSApple OSS Distributions 			// Do not restart timer until after the tickle request has been
3459*c54f35caSApple OSS Distributions 			// processed.
3460*c54f35caSApple OSS Distributions 
3461*c54f35caSApple OSS Distributions 			restartTimer = false;
3462*c54f35caSApple OSS Distributions 		}
3463*c54f35caSApple OSS Distributions 	}
3464*c54f35caSApple OSS Distributions 
3465*c54f35caSApple OSS Distributions 	if (fAdvisoryTickled) {
3466*c54f35caSApple OSS Distributions 		fAdvisoryTickled = false;
3467*c54f35caSApple OSS Distributions 	} else if (fHasAdvisoryDesire) {
3468*c54f35caSApple OSS Distributions 		// Want new tickles to turn into pm request after we drop the lock
3469*c54f35caSApple OSS Distributions 		fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3470*c54f35caSApple OSS Distributions 
3471*c54f35caSApple OSS Distributions 		tickleFlags = kTickleTypeAdvisory | kTickleTypePowerDrop;
3472*c54f35caSApple OSS Distributions 		request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3473*c54f35caSApple OSS Distributions 		if (request) {
3474*c54f35caSApple OSS Distributions 			request->fArg0 = (void *)(uintptr_t) fIdleTimerGeneration;
3475*c54f35caSApple OSS Distributions 			request->fArg1 = (void *)(uintptr_t) tickleFlags;
3476*c54f35caSApple OSS Distributions 			request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3477*c54f35caSApple OSS Distributions 			submitPMRequest( request );
3478*c54f35caSApple OSS Distributions 
3479*c54f35caSApple OSS Distributions 			// Do not restart timer until after the tickle request has been
3480*c54f35caSApple OSS Distributions 			// processed.
3481*c54f35caSApple OSS Distributions 
3482*c54f35caSApple OSS Distributions 			restartTimer = false;
3483*c54f35caSApple OSS Distributions 		}
3484*c54f35caSApple OSS Distributions 	}
3485*c54f35caSApple OSS Distributions 
3486*c54f35caSApple OSS Distributions 	IOLockUnlock(fActivityLock);
3487*c54f35caSApple OSS Distributions 
3488*c54f35caSApple OSS Distributions 	if (restartTimer) {
3489*c54f35caSApple OSS Distributions 		start_PM_idle_timer();
3490*c54f35caSApple OSS Distributions 	}
3491*c54f35caSApple OSS Distributions }
3492*c54f35caSApple OSS Distributions 
3493*c54f35caSApple OSS Distributions #ifndef __LP64__
3494*c54f35caSApple OSS Distributions //*********************************************************************************
3495*c54f35caSApple OSS Distributions // [deprecated] PM_idle_timer_expiration
3496*c54f35caSApple OSS Distributions //*********************************************************************************
3497*c54f35caSApple OSS Distributions 
3498*c54f35caSApple OSS Distributions void
PM_idle_timer_expiration(void)3499*c54f35caSApple OSS Distributions IOService::PM_idle_timer_expiration( void )
3500*c54f35caSApple OSS Distributions {
3501*c54f35caSApple OSS Distributions }
3502*c54f35caSApple OSS Distributions 
3503*c54f35caSApple OSS Distributions //*********************************************************************************
3504*c54f35caSApple OSS Distributions // [deprecated] command_received
3505*c54f35caSApple OSS Distributions //*********************************************************************************
3506*c54f35caSApple OSS Distributions 
3507*c54f35caSApple OSS Distributions void
command_received(void * statePtr,void *,void *,void *)3508*c54f35caSApple OSS Distributions IOService::command_received( void *statePtr, void *, void *, void * )
3509*c54f35caSApple OSS Distributions {
3510*c54f35caSApple OSS Distributions }
3511*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
3512*c54f35caSApple OSS Distributions 
3513*c54f35caSApple OSS Distributions //*********************************************************************************
3514*c54f35caSApple OSS Distributions // [public] setAggressiveness
3515*c54f35caSApple OSS Distributions //
3516*c54f35caSApple OSS Distributions // Pass on the input parameters to all power domain children. All those which are
3517*c54f35caSApple OSS Distributions // power domains will pass it on to their children, etc.
3518*c54f35caSApple OSS Distributions //*********************************************************************************
3519*c54f35caSApple OSS Distributions 
3520*c54f35caSApple OSS Distributions IOReturn
setAggressiveness(unsigned long type,unsigned long newLevel)3521*c54f35caSApple OSS Distributions IOService::setAggressiveness( unsigned long type, unsigned long newLevel )
3522*c54f35caSApple OSS Distributions {
3523*c54f35caSApple OSS Distributions 	return kIOReturnSuccess;
3524*c54f35caSApple OSS Distributions }
3525*c54f35caSApple OSS Distributions 
3526*c54f35caSApple OSS Distributions //*********************************************************************************
3527*c54f35caSApple OSS Distributions // [public] getAggressiveness
3528*c54f35caSApple OSS Distributions //
3529*c54f35caSApple OSS Distributions // Called by the user client.
3530*c54f35caSApple OSS Distributions //*********************************************************************************
3531*c54f35caSApple OSS Distributions 
3532*c54f35caSApple OSS Distributions IOReturn
getAggressiveness(unsigned long type,unsigned long * currentLevel)3533*c54f35caSApple OSS Distributions IOService::getAggressiveness( unsigned long type, unsigned long * currentLevel )
3534*c54f35caSApple OSS Distributions {
3535*c54f35caSApple OSS Distributions 	IOPMrootDomain *    rootDomain = getPMRootDomain();
3536*c54f35caSApple OSS Distributions 
3537*c54f35caSApple OSS Distributions 	if (!rootDomain) {
3538*c54f35caSApple OSS Distributions 		return kIOReturnNotReady;
3539*c54f35caSApple OSS Distributions 	}
3540*c54f35caSApple OSS Distributions 
3541*c54f35caSApple OSS Distributions 	return rootDomain->getAggressiveness( type, currentLevel );
3542*c54f35caSApple OSS Distributions }
3543*c54f35caSApple OSS Distributions 
3544*c54f35caSApple OSS Distributions //*********************************************************************************
3545*c54f35caSApple OSS Distributions // [public] getPowerState
3546*c54f35caSApple OSS Distributions //
3547*c54f35caSApple OSS Distributions //*********************************************************************************
3548*c54f35caSApple OSS Distributions 
3549*c54f35caSApple OSS Distributions UInt32
getPowerState(void)3550*c54f35caSApple OSS Distributions IOService::getPowerState( void )
3551*c54f35caSApple OSS Distributions {
3552*c54f35caSApple OSS Distributions 	if (!initialized) {
3553*c54f35caSApple OSS Distributions 		return kPowerStateZero;
3554*c54f35caSApple OSS Distributions 	}
3555*c54f35caSApple OSS Distributions 
3556*c54f35caSApple OSS Distributions 	return (UInt32) fCurrentPowerState;
3557*c54f35caSApple OSS Distributions }
3558*c54f35caSApple OSS Distributions 
3559*c54f35caSApple OSS Distributions #ifndef __LP64__
3560*c54f35caSApple OSS Distributions //*********************************************************************************
3561*c54f35caSApple OSS Distributions // [deprecated] systemWake
3562*c54f35caSApple OSS Distributions //
3563*c54f35caSApple OSS Distributions // Pass this to all power domain children. All those which are
3564*c54f35caSApple OSS Distributions // power domains will pass it on to their children, etc.
3565*c54f35caSApple OSS Distributions //*********************************************************************************
3566*c54f35caSApple OSS Distributions 
3567*c54f35caSApple OSS Distributions IOReturn
systemWake(void)3568*c54f35caSApple OSS Distributions IOService::systemWake( void )
3569*c54f35caSApple OSS Distributions {
3570*c54f35caSApple OSS Distributions 	OSIterator *        iter;
3571*c54f35caSApple OSS Distributions 	OSObject *          next;
3572*c54f35caSApple OSS Distributions 	IOPowerConnection * connection;
3573*c54f35caSApple OSS Distributions 	IOService *         theChild;
3574*c54f35caSApple OSS Distributions 
3575*c54f35caSApple OSS Distributions 	iter = getChildIterator(gIOPowerPlane);
3576*c54f35caSApple OSS Distributions 	if (iter) {
3577*c54f35caSApple OSS Distributions 		while ((next = iter->getNextObject())) {
3578*c54f35caSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, next))) {
3579*c54f35caSApple OSS Distributions 				if (connection->getReadyFlag() == false) {
3580*c54f35caSApple OSS Distributions 					PM_LOG3("[%s] %s: connection not ready\n",
3581*c54f35caSApple OSS Distributions 					    getName(), __FUNCTION__);
3582*c54f35caSApple OSS Distributions 					continue;
3583*c54f35caSApple OSS Distributions 				}
3584*c54f35caSApple OSS Distributions 
3585*c54f35caSApple OSS Distributions 				theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
3586*c54f35caSApple OSS Distributions 				if (theChild) {
3587*c54f35caSApple OSS Distributions 					theChild->systemWake();
3588*c54f35caSApple OSS Distributions 					theChild->release();
3589*c54f35caSApple OSS Distributions 				}
3590*c54f35caSApple OSS Distributions 			}
3591*c54f35caSApple OSS Distributions 		}
3592*c54f35caSApple OSS Distributions 		iter->release();
3593*c54f35caSApple OSS Distributions 	}
3594*c54f35caSApple OSS Distributions 
3595*c54f35caSApple OSS Distributions 	if (fControllingDriver != NULL) {
3596*c54f35caSApple OSS Distributions 		if (fControllingDriver->didYouWakeSystem()) {
3597*c54f35caSApple OSS Distributions 			makeUsable();
3598*c54f35caSApple OSS Distributions 		}
3599*c54f35caSApple OSS Distributions 	}
3600*c54f35caSApple OSS Distributions 
3601*c54f35caSApple OSS Distributions 	return IOPMNoErr;
3602*c54f35caSApple OSS Distributions }
3603*c54f35caSApple OSS Distributions 
3604*c54f35caSApple OSS Distributions //*********************************************************************************
3605*c54f35caSApple OSS Distributions // [deprecated] temperatureCriticalForZone
3606*c54f35caSApple OSS Distributions //*********************************************************************************
3607*c54f35caSApple OSS Distributions 
3608*c54f35caSApple OSS Distributions IOReturn
temperatureCriticalForZone(IOService * whichZone)3609*c54f35caSApple OSS Distributions IOService::temperatureCriticalForZone( IOService * whichZone )
3610*c54f35caSApple OSS Distributions {
3611*c54f35caSApple OSS Distributions 	IOService * theParent;
3612*c54f35caSApple OSS Distributions 	IOService * theNub;
3613*c54f35caSApple OSS Distributions 
3614*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogCriticalTemp, 0, 0);
3615*c54f35caSApple OSS Distributions 
3616*c54f35caSApple OSS Distributions 	if (inPlane(gIOPowerPlane) && !IS_PM_ROOT) {
3617*c54f35caSApple OSS Distributions 		theNub = (IOService *)copyParentEntry(gIOPowerPlane);
3618*c54f35caSApple OSS Distributions 		if (theNub) {
3619*c54f35caSApple OSS Distributions 			theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
3620*c54f35caSApple OSS Distributions 			theNub->release();
3621*c54f35caSApple OSS Distributions 			if (theParent) {
3622*c54f35caSApple OSS Distributions 				theParent->temperatureCriticalForZone(whichZone);
3623*c54f35caSApple OSS Distributions 				theParent->release();
3624*c54f35caSApple OSS Distributions 			}
3625*c54f35caSApple OSS Distributions 		}
3626*c54f35caSApple OSS Distributions 	}
3627*c54f35caSApple OSS Distributions 	return IOPMNoErr;
3628*c54f35caSApple OSS Distributions }
3629*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
3630*c54f35caSApple OSS Distributions 
3631*c54f35caSApple OSS Distributions // MARK: -
3632*c54f35caSApple OSS Distributions // MARK: Power Change (Common)
3633*c54f35caSApple OSS Distributions 
3634*c54f35caSApple OSS Distributions //*********************************************************************************
3635*c54f35caSApple OSS Distributions // [private] startPowerChange
3636*c54f35caSApple OSS Distributions //
3637*c54f35caSApple OSS Distributions // All power state changes starts here.
3638*c54f35caSApple OSS Distributions //*********************************************************************************
3639*c54f35caSApple OSS Distributions 
3640*c54f35caSApple OSS Distributions IOReturn
startPowerChange(IOPMPowerChangeFlags changeFlags,IOPMPowerStateIndex powerState,IOPMPowerFlags domainFlags,IOPowerConnection * parentConnection,IOPMPowerFlags parentFlags)3641*c54f35caSApple OSS Distributions IOService::startPowerChange(
3642*c54f35caSApple OSS Distributions 	IOPMPowerChangeFlags    changeFlags,
3643*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex     powerState,
3644*c54f35caSApple OSS Distributions 	IOPMPowerFlags          domainFlags,
3645*c54f35caSApple OSS Distributions 	IOPowerConnection *     parentConnection,
3646*c54f35caSApple OSS Distributions 	IOPMPowerFlags          parentFlags )
3647*c54f35caSApple OSS Distributions {
3648*c54f35caSApple OSS Distributions 	uint32_t savedPMActionsState;
3649*c54f35caSApple OSS Distributions 
3650*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
3651*c54f35caSApple OSS Distributions 	assert( fMachineState == kIOPM_Finished );
3652*c54f35caSApple OSS Distributions 	assert( powerState < fNumberOfPowerStates );
3653*c54f35caSApple OSS Distributions 
3654*c54f35caSApple OSS Distributions 	if (powerState >= fNumberOfPowerStates) {
3655*c54f35caSApple OSS Distributions 		return IOPMAckImplied;
3656*c54f35caSApple OSS Distributions 	}
3657*c54f35caSApple OSS Distributions 
3658*c54f35caSApple OSS Distributions 	fIsPreChange = true;
3659*c54f35caSApple OSS Distributions 	savedPMActionsState = fPMActions.state;
3660*c54f35caSApple OSS Distributions 	PM_ACTION_CHANGE(actionPowerChangeOverride, &powerState, &changeFlags);
3661*c54f35caSApple OSS Distributions 
3662*c54f35caSApple OSS Distributions 	// rdar://problem/55040032
3663*c54f35caSApple OSS Distributions 	// Schedule a power adjustment after removing the power clamp
3664*c54f35caSApple OSS Distributions 	// to inform our power parent(s) about our latest desired domain
3665*c54f35caSApple OSS Distributions 	// power state. For a self-initiated change, let OurChangeStart()
3666*c54f35caSApple OSS Distributions 	// automatically request parent power when necessary.
3667*c54f35caSApple OSS Distributions 	if (!fAdjustPowerScheduled &&
3668*c54f35caSApple OSS Distributions 	    ((changeFlags & kIOPMSelfInitiated) == 0) &&
3669*c54f35caSApple OSS Distributions 	    ((fPMActions.state & kPMActionsStatePowerClamped) == 0) &&
3670*c54f35caSApple OSS Distributions 	    ((savedPMActionsState & kPMActionsStatePowerClamped) != 0)) {
3671*c54f35caSApple OSS Distributions 		IOPMRequest * request = acquirePMRequest(this, kIOPMRequestTypeAdjustPowerState);
3672*c54f35caSApple OSS Distributions 		if (request) {
3673*c54f35caSApple OSS Distributions 			submitPMRequest(request);
3674*c54f35caSApple OSS Distributions 			fAdjustPowerScheduled = true;
3675*c54f35caSApple OSS Distributions 		}
3676*c54f35caSApple OSS Distributions 	}
3677*c54f35caSApple OSS Distributions 
3678*c54f35caSApple OSS Distributions 	if (changeFlags & kIOPMExpireIdleTimer) {
3679*c54f35caSApple OSS Distributions 		// Root domain requested removal of tickle influence
3680*c54f35caSApple OSS Distributions 		if (StateOrder(fDeviceDesire) > StateOrder(powerState)) {
3681*c54f35caSApple OSS Distributions 			// Reset device desire down to the clamped power state
3682*c54f35caSApple OSS Distributions 			updatePowerClient(gIOPMPowerClientDevice, powerState);
3683*c54f35caSApple OSS Distributions 			computeDesiredState(kPowerStateZero, true);
3684*c54f35caSApple OSS Distributions 
3685*c54f35caSApple OSS Distributions 			// Invalidate tickle cache so the next tickle will issue a request
3686*c54f35caSApple OSS Distributions 			IOLockLock(fActivityLock);
3687*c54f35caSApple OSS Distributions 			fDeviceWasActive = false;
3688*c54f35caSApple OSS Distributions 			fActivityTicklePowerState = kInvalidTicklePowerState;
3689*c54f35caSApple OSS Distributions 			IOLockUnlock(fActivityLock);
3690*c54f35caSApple OSS Distributions 
3691*c54f35caSApple OSS Distributions 			fIdleTimerMinPowerState = kPowerStateZero;
3692*c54f35caSApple OSS Distributions 		}
3693*c54f35caSApple OSS Distributions 	}
3694*c54f35caSApple OSS Distributions 
3695*c54f35caSApple OSS Distributions 	// Root domain's override handler may cancel the power change by
3696*c54f35caSApple OSS Distributions 	// setting the kIOPMNotDone flag.
3697*c54f35caSApple OSS Distributions 
3698*c54f35caSApple OSS Distributions 	if (changeFlags & kIOPMNotDone) {
3699*c54f35caSApple OSS Distributions 		return IOPMAckImplied;
3700*c54f35caSApple OSS Distributions 	}
3701*c54f35caSApple OSS Distributions 
3702*c54f35caSApple OSS Distributions 	// Forks to either Driver or Parent initiated power change paths.
3703*c54f35caSApple OSS Distributions 
3704*c54f35caSApple OSS Distributions 	fHeadNoteChangeFlags      = changeFlags;
3705*c54f35caSApple OSS Distributions 	fHeadNotePowerState       = powerState;
3706*c54f35caSApple OSS Distributions 	fHeadNotePowerArrayEntry  = &fPowerStates[powerState];
3707*c54f35caSApple OSS Distributions 	fHeadNoteParentConnection = NULL;
3708*c54f35caSApple OSS Distributions 
3709*c54f35caSApple OSS Distributions 	if (changeFlags & kIOPMSelfInitiated) {
3710*c54f35caSApple OSS Distributions 		if (changeFlags & kIOPMSynchronize) {
3711*c54f35caSApple OSS Distributions 			OurSyncStart();
3712*c54f35caSApple OSS Distributions 		} else {
3713*c54f35caSApple OSS Distributions 			OurChangeStart();
3714*c54f35caSApple OSS Distributions 		}
3715*c54f35caSApple OSS Distributions 		return 0;
3716*c54f35caSApple OSS Distributions 	} else {
3717*c54f35caSApple OSS Distributions 		assert(changeFlags & kIOPMParentInitiated);
3718*c54f35caSApple OSS Distributions 		fHeadNoteDomainFlags = domainFlags;
3719*c54f35caSApple OSS Distributions 		fHeadNoteParentFlags = parentFlags;
3720*c54f35caSApple OSS Distributions 		fHeadNoteParentConnection = parentConnection;
3721*c54f35caSApple OSS Distributions 		return ParentChangeStart();
3722*c54f35caSApple OSS Distributions 	}
3723*c54f35caSApple OSS Distributions }
3724*c54f35caSApple OSS Distributions 
3725*c54f35caSApple OSS Distributions //*********************************************************************************
3726*c54f35caSApple OSS Distributions // [private] notifyInterestedDrivers
3727*c54f35caSApple OSS Distributions //*********************************************************************************
3728*c54f35caSApple OSS Distributions 
3729*c54f35caSApple OSS Distributions bool
notifyInterestedDrivers(void)3730*c54f35caSApple OSS Distributions IOService::notifyInterestedDrivers( void )
3731*c54f35caSApple OSS Distributions {
3732*c54f35caSApple OSS Distributions 	IOPMinformee *      informee;
3733*c54f35caSApple OSS Distributions 	IOPMinformeeList *  list = fInterestedDrivers;
3734*c54f35caSApple OSS Distributions 	DriverCallParam *   param;
3735*c54f35caSApple OSS Distributions 	unsigned long       numItems;
3736*c54f35caSApple OSS Distributions 	uint32_t            count;
3737*c54f35caSApple OSS Distributions 	uint32_t            skipCnt = 0;
3738*c54f35caSApple OSS Distributions 
3739*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
3740*c54f35caSApple OSS Distributions 	assert( fDriverCallParamCount == 0 );
3741*c54f35caSApple OSS Distributions 	assert( fHeadNotePendingAcks == 0 );
3742*c54f35caSApple OSS Distributions 
3743*c54f35caSApple OSS Distributions 	fHeadNotePendingAcks = 0;
3744*c54f35caSApple OSS Distributions 
3745*c54f35caSApple OSS Distributions 	numItems = list->numberOfItems();
3746*c54f35caSApple OSS Distributions 	if (!numItems || ((uint32_t) numItems != numItems)) {
3747*c54f35caSApple OSS Distributions 		goto done; // interested drivers count out of range
3748*c54f35caSApple OSS Distributions 	}
3749*c54f35caSApple OSS Distributions 	count = (uint32_t) numItems;
3750*c54f35caSApple OSS Distributions 
3751*c54f35caSApple OSS Distributions 	// Allocate an array of interested drivers and their return values
3752*c54f35caSApple OSS Distributions 	// for the callout thread. Everything else is still "owned" by the
3753*c54f35caSApple OSS Distributions 	// PM work loop, which can run to process acknowledgePowerChange()
3754*c54f35caSApple OSS Distributions 	// responses.
3755*c54f35caSApple OSS Distributions 
3756*c54f35caSApple OSS Distributions 	param = (DriverCallParam *) fDriverCallParamPtr;
3757*c54f35caSApple OSS Distributions 	if (count > fDriverCallParamSlots) {
3758*c54f35caSApple OSS Distributions 		if (fDriverCallParamSlots) {
3759*c54f35caSApple OSS Distributions 			assert(fDriverCallParamPtr);
3760*c54f35caSApple OSS Distributions 			IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
3761*c54f35caSApple OSS Distributions 			fDriverCallParamPtr = NULL;
3762*c54f35caSApple OSS Distributions 			fDriverCallParamSlots = 0;
3763*c54f35caSApple OSS Distributions 		}
3764*c54f35caSApple OSS Distributions 
3765*c54f35caSApple OSS Distributions 		param = IONew(DriverCallParam, count);
3766*c54f35caSApple OSS Distributions 		if (!param) {
3767*c54f35caSApple OSS Distributions 			goto done; // no memory
3768*c54f35caSApple OSS Distributions 		}
3769*c54f35caSApple OSS Distributions 		fDriverCallParamPtr   = (void *) param;
3770*c54f35caSApple OSS Distributions 		fDriverCallParamSlots = count;
3771*c54f35caSApple OSS Distributions 	}
3772*c54f35caSApple OSS Distributions 
3773*c54f35caSApple OSS Distributions 	informee = list->firstInList();
3774*c54f35caSApple OSS Distributions 	assert(informee);
3775*c54f35caSApple OSS Distributions 	for (IOItemCount i = 0, arrayIdx = 0; i < count; i++) {
3776*c54f35caSApple OSS Distributions 		if (fInitialSetPowerState || (fHeadNoteChangeFlags & kIOPMInitialPowerChange)) {
3777*c54f35caSApple OSS Distributions 			// Skip notifying self, if 'kIOPMInitialDeviceState' is set and
3778*c54f35caSApple OSS Distributions 			// this is the initial power state change
3779*c54f35caSApple OSS Distributions 			if ((this == informee->whatObject) &&
3780*c54f35caSApple OSS Distributions 			    (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState)) {
3781*c54f35caSApple OSS Distributions 				skipCnt++;
3782*c54f35caSApple OSS Distributions 				continue;
3783*c54f35caSApple OSS Distributions 			}
3784*c54f35caSApple OSS Distributions 		}
3785*c54f35caSApple OSS Distributions 		informee->timer = -1;
3786*c54f35caSApple OSS Distributions 		param[arrayIdx].Target = informee;
3787*c54f35caSApple OSS Distributions 		informee->retain();
3788*c54f35caSApple OSS Distributions 		informee = list->nextInList( informee );
3789*c54f35caSApple OSS Distributions 		arrayIdx++;
3790*c54f35caSApple OSS Distributions 	}
3791*c54f35caSApple OSS Distributions 
3792*c54f35caSApple OSS Distributions 	count -= skipCnt;
3793*c54f35caSApple OSS Distributions 	if (!count) {
3794*c54f35caSApple OSS Distributions 		goto done;
3795*c54f35caSApple OSS Distributions 	}
3796*c54f35caSApple OSS Distributions 	fDriverCallParamCount = count;
3797*c54f35caSApple OSS Distributions 	fHeadNotePendingAcks  = count;
3798*c54f35caSApple OSS Distributions 
3799*c54f35caSApple OSS Distributions 	// Block state machine and wait for callout completion.
3800*c54f35caSApple OSS Distributions 	assert(!fDriverCallBusy);
3801*c54f35caSApple OSS Distributions 	fDriverCallBusy = true;
3802*c54f35caSApple OSS Distributions 	thread_call_enter( fDriverCallEntry );
3803*c54f35caSApple OSS Distributions 	return true;
3804*c54f35caSApple OSS Distributions 
3805*c54f35caSApple OSS Distributions done:
3806*c54f35caSApple OSS Distributions 	// Return false if there are no interested drivers or could not schedule
3807*c54f35caSApple OSS Distributions 	// callout thread due to error.
3808*c54f35caSApple OSS Distributions 	return false;
3809*c54f35caSApple OSS Distributions }
3810*c54f35caSApple OSS Distributions 
3811*c54f35caSApple OSS Distributions //*********************************************************************************
3812*c54f35caSApple OSS Distributions // [private] notifyInterestedDriversDone
3813*c54f35caSApple OSS Distributions //*********************************************************************************
3814*c54f35caSApple OSS Distributions 
3815*c54f35caSApple OSS Distributions void
notifyInterestedDriversDone(void)3816*c54f35caSApple OSS Distributions IOService::notifyInterestedDriversDone( void )
3817*c54f35caSApple OSS Distributions {
3818*c54f35caSApple OSS Distributions 	IOPMinformee *      informee;
3819*c54f35caSApple OSS Distributions 	IOItemCount         count;
3820*c54f35caSApple OSS Distributions 	DriverCallParam *   param;
3821*c54f35caSApple OSS Distributions 	IOReturn            result;
3822*c54f35caSApple OSS Distributions 	int                 maxTimeout = 0;
3823*c54f35caSApple OSS Distributions 
3824*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
3825*c54f35caSApple OSS Distributions 	assert( fDriverCallBusy == false );
3826*c54f35caSApple OSS Distributions 	assert( fMachineState == kIOPM_DriverThreadCallDone );
3827*c54f35caSApple OSS Distributions 
3828*c54f35caSApple OSS Distributions 	param = (DriverCallParam *) fDriverCallParamPtr;
3829*c54f35caSApple OSS Distributions 	count = fDriverCallParamCount;
3830*c54f35caSApple OSS Distributions 
3831*c54f35caSApple OSS Distributions 	if (param && count) {
3832*c54f35caSApple OSS Distributions 		for (IOItemCount i = 0; i < count; i++, param++) {
3833*c54f35caSApple OSS Distributions 			informee = (IOPMinformee *) param->Target;
3834*c54f35caSApple OSS Distributions 			result   = param->Result;
3835*c54f35caSApple OSS Distributions 
3836*c54f35caSApple OSS Distributions 			if ((result == IOPMAckImplied) || (result < 0)) {
3837*c54f35caSApple OSS Distributions 				// Interested driver return IOPMAckImplied.
3838*c54f35caSApple OSS Distributions 				// If informee timer is zero, it must have de-registered
3839*c54f35caSApple OSS Distributions 				// interest during the thread callout. That also drops
3840*c54f35caSApple OSS Distributions 				// the pending ack count.
3841*c54f35caSApple OSS Distributions 
3842*c54f35caSApple OSS Distributions 				if (fHeadNotePendingAcks && informee->timer) {
3843*c54f35caSApple OSS Distributions 					fHeadNotePendingAcks--;
3844*c54f35caSApple OSS Distributions 				}
3845*c54f35caSApple OSS Distributions 
3846*c54f35caSApple OSS Distributions 				informee->timer = 0;
3847*c54f35caSApple OSS Distributions 			} else if (informee->timer) {
3848*c54f35caSApple OSS Distributions 				assert(informee->timer == -1);
3849*c54f35caSApple OSS Distributions 
3850*c54f35caSApple OSS Distributions 				// Driver has not acked, and has returned a positive result.
3851*c54f35caSApple OSS Distributions 				// Enforce a minimum permissible timeout value.
3852*c54f35caSApple OSS Distributions 				// Make the min value large enough so timeout is less likely
3853*c54f35caSApple OSS Distributions 				// to occur if a driver misinterpreted that the return value
3854*c54f35caSApple OSS Distributions 				// should be in microsecond units.  And make it large enough
3855*c54f35caSApple OSS Distributions 				// to be noticeable if a driver neglects to ack.
3856*c54f35caSApple OSS Distributions 
3857*c54f35caSApple OSS Distributions 				if (result < kMinAckTimeoutTicks) {
3858*c54f35caSApple OSS Distributions 					result = kMinAckTimeoutTicks;
3859*c54f35caSApple OSS Distributions 				}
3860*c54f35caSApple OSS Distributions 
3861*c54f35caSApple OSS Distributions 				informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
3862*c54f35caSApple OSS Distributions 				if (result > maxTimeout) {
3863*c54f35caSApple OSS Distributions 					maxTimeout = result;
3864*c54f35caSApple OSS Distributions 				}
3865*c54f35caSApple OSS Distributions 			}
3866*c54f35caSApple OSS Distributions 			// else, child has already acked or driver has removed interest,
3867*c54f35caSApple OSS Distributions 			// and head_note_pendingAcks decremented.
3868*c54f35caSApple OSS Distributions 			// informee may have been removed from the interested drivers list,
3869*c54f35caSApple OSS Distributions 			// thus the informee must be retained across the callout.
3870*c54f35caSApple OSS Distributions 
3871*c54f35caSApple OSS Distributions 			informee->release();
3872*c54f35caSApple OSS Distributions 		}
3873*c54f35caSApple OSS Distributions 
3874*c54f35caSApple OSS Distributions 		fDriverCallParamCount = 0;
3875*c54f35caSApple OSS Distributions 
3876*c54f35caSApple OSS Distributions 		if (fHeadNotePendingAcks) {
3877*c54f35caSApple OSS Distributions 			OUR_PMLog(kPMLogStartAckTimer, 0, 0);
3878*c54f35caSApple OSS Distributions 			start_ack_timer();
3879*c54f35caSApple OSS Distributions 			getPMRootDomain()->reset_watchdog_timer(this, maxTimeout / USEC_PER_SEC + 1);
3880*c54f35caSApple OSS Distributions 		}
3881*c54f35caSApple OSS Distributions 	}
3882*c54f35caSApple OSS Distributions 
3883*c54f35caSApple OSS Distributions 	MS_POP(); // pop the machine state passed to notifyAll()
3884*c54f35caSApple OSS Distributions 
3885*c54f35caSApple OSS Distributions 	// If interest acks are outstanding, block the state machine until
3886*c54f35caSApple OSS Distributions 	// fHeadNotePendingAcks drops to zero before notifying root domain.
3887*c54f35caSApple OSS Distributions 	// Otherwise notify root domain directly.
3888*c54f35caSApple OSS Distributions 
3889*c54f35caSApple OSS Distributions 	if (!fHeadNotePendingAcks) {
3890*c54f35caSApple OSS Distributions 		notifyRootDomain();
3891*c54f35caSApple OSS Distributions 	} else {
3892*c54f35caSApple OSS Distributions 		MS_PUSH(fMachineState);
3893*c54f35caSApple OSS Distributions 		fMachineState = kIOPM_NotifyChildrenStart;
3894*c54f35caSApple OSS Distributions 	}
3895*c54f35caSApple OSS Distributions }
3896*c54f35caSApple OSS Distributions 
3897*c54f35caSApple OSS Distributions //*********************************************************************************
3898*c54f35caSApple OSS Distributions // [private] notifyRootDomain
3899*c54f35caSApple OSS Distributions //*********************************************************************************
3900*c54f35caSApple OSS Distributions 
3901*c54f35caSApple OSS Distributions void
notifyRootDomain(void)3902*c54f35caSApple OSS Distributions IOService::notifyRootDomain( void )
3903*c54f35caSApple OSS Distributions {
3904*c54f35caSApple OSS Distributions 	assert( fDriverCallBusy == false );
3905*c54f35caSApple OSS Distributions 
3906*c54f35caSApple OSS Distributions 	// Only for root domain in the will-change phase.
3907*c54f35caSApple OSS Distributions 	// On a power up, don't notify children right after the interested drivers.
3908*c54f35caSApple OSS Distributions 	// Perform setPowerState() first, then notify the children.
3909*c54f35caSApple OSS Distributions 	if (!IS_ROOT_DOMAIN || (fMachineState != kIOPM_OurChangeSetPowerState)) {
3910*c54f35caSApple OSS Distributions 		notifyChildren();
3911*c54f35caSApple OSS Distributions 		return;
3912*c54f35caSApple OSS Distributions 	}
3913*c54f35caSApple OSS Distributions 
3914*c54f35caSApple OSS Distributions 	MS_PUSH(fMachineState); // push notifyAll() machine state
3915*c54f35caSApple OSS Distributions 	fMachineState = kIOPM_DriverThreadCallDone;
3916*c54f35caSApple OSS Distributions 
3917*c54f35caSApple OSS Distributions 	// Call IOPMrootDomain::willNotifyPowerChildren() on a thread call
3918*c54f35caSApple OSS Distributions 	// to avoid a deadlock.
3919*c54f35caSApple OSS Distributions 	fDriverCallReason = kRootDomainInformPreChange;
3920*c54f35caSApple OSS Distributions 	fDriverCallBusy   = true;
3921*c54f35caSApple OSS Distributions 	thread_call_enter( fDriverCallEntry );
3922*c54f35caSApple OSS Distributions }
3923*c54f35caSApple OSS Distributions 
3924*c54f35caSApple OSS Distributions void
notifyRootDomainDone(void)3925*c54f35caSApple OSS Distributions IOService::notifyRootDomainDone( void )
3926*c54f35caSApple OSS Distributions {
3927*c54f35caSApple OSS Distributions 	assert( fDriverCallBusy == false );
3928*c54f35caSApple OSS Distributions 	assert( fMachineState == kIOPM_DriverThreadCallDone );
3929*c54f35caSApple OSS Distributions 
3930*c54f35caSApple OSS Distributions 	MS_POP(); // pop notifyAll() machine state
3931*c54f35caSApple OSS Distributions 	notifyChildren();
3932*c54f35caSApple OSS Distributions }
3933*c54f35caSApple OSS Distributions 
3934*c54f35caSApple OSS Distributions //*********************************************************************************
3935*c54f35caSApple OSS Distributions // [private] notifyChildren
3936*c54f35caSApple OSS Distributions //*********************************************************************************
3937*c54f35caSApple OSS Distributions 
3938*c54f35caSApple OSS Distributions void
notifyChildren(void)3939*c54f35caSApple OSS Distributions IOService::notifyChildren( void )
3940*c54f35caSApple OSS Distributions {
3941*c54f35caSApple OSS Distributions 	OSIterator *        iter;
3942*c54f35caSApple OSS Distributions 	OSObject *          next;
3943*c54f35caSApple OSS Distributions 	IOPowerConnection * connection;
3944*c54f35caSApple OSS Distributions 	OSArray *           children = NULL;
3945*c54f35caSApple OSS Distributions 	IOPMrootDomain *    rootDomain;
3946*c54f35caSApple OSS Distributions 	bool                delayNotify = false;
3947*c54f35caSApple OSS Distributions 
3948*c54f35caSApple OSS Distributions 	if ((fHeadNotePowerState != fCurrentPowerState) &&
3949*c54f35caSApple OSS Distributions 	    (IS_POWER_DROP == fIsPreChange) &&
3950*c54f35caSApple OSS Distributions 	    ((rootDomain = getPMRootDomain()) == this)) {
3951*c54f35caSApple OSS Distributions 		rootDomain->tracePoint( IS_POWER_DROP ?
3952*c54f35caSApple OSS Distributions 		    kIOPMTracePointSleepPowerPlaneDrivers :
3953*c54f35caSApple OSS Distributions 		    kIOPMTracePointWakePowerPlaneDrivers  );
3954*c54f35caSApple OSS Distributions 	}
3955*c54f35caSApple OSS Distributions 
3956*c54f35caSApple OSS Distributions 	if (fStrictTreeOrder) {
3957*c54f35caSApple OSS Distributions 		children = OSArray::withCapacity(8);
3958*c54f35caSApple OSS Distributions 	}
3959*c54f35caSApple OSS Distributions 
3960*c54f35caSApple OSS Distributions 	// Sum child power consumption in notifyChild()
3961*c54f35caSApple OSS Distributions 	fHeadNotePowerArrayEntry->staticPower = 0;
3962*c54f35caSApple OSS Distributions 
3963*c54f35caSApple OSS Distributions 	iter = getChildIterator(gIOPowerPlane);
3964*c54f35caSApple OSS Distributions 	if (iter) {
3965*c54f35caSApple OSS Distributions 		while ((next = iter->getNextObject())) {
3966*c54f35caSApple OSS Distributions 			if ((connection = OSDynamicCast(IOPowerConnection, next))) {
3967*c54f35caSApple OSS Distributions 				if (connection->getReadyFlag() == false) {
3968*c54f35caSApple OSS Distributions 					PM_LOG3("[%s] %s: connection not ready\n",
3969*c54f35caSApple OSS Distributions 					    getName(), __FUNCTION__);
3970*c54f35caSApple OSS Distributions 					continue;
3971*c54f35caSApple OSS Distributions 				}
3972*c54f35caSApple OSS Distributions 
3973*c54f35caSApple OSS Distributions 				// Mechanism to postpone the did-change notification to
3974*c54f35caSApple OSS Distributions 				// certain power children to order those children last.
3975*c54f35caSApple OSS Distributions 				// Cannot be used together with strict tree ordering.
3976*c54f35caSApple OSS Distributions 
3977*c54f35caSApple OSS Distributions 				if (!fIsPreChange &&
3978*c54f35caSApple OSS Distributions 				    connection->delayChildNotification &&
3979*c54f35caSApple OSS Distributions 				    getPMRootDomain()->shouldDelayChildNotification(this)) {
3980*c54f35caSApple OSS Distributions 					if (!children) {
3981*c54f35caSApple OSS Distributions 						children = OSArray::withCapacity(8);
3982*c54f35caSApple OSS Distributions 						if (children) {
3983*c54f35caSApple OSS Distributions 							delayNotify = true;
3984*c54f35caSApple OSS Distributions 						}
3985*c54f35caSApple OSS Distributions 					}
3986*c54f35caSApple OSS Distributions 					if (delayNotify) {
3987*c54f35caSApple OSS Distributions 						children->setObject( connection );
3988*c54f35caSApple OSS Distributions 						continue;
3989*c54f35caSApple OSS Distributions 					}
3990*c54f35caSApple OSS Distributions 				}
3991*c54f35caSApple OSS Distributions 
3992*c54f35caSApple OSS Distributions 				if (!delayNotify && children) {
3993*c54f35caSApple OSS Distributions 					children->setObject( connection );
3994*c54f35caSApple OSS Distributions 				} else {
3995*c54f35caSApple OSS Distributions 					notifyChild( connection );
3996*c54f35caSApple OSS Distributions 				}
3997*c54f35caSApple OSS Distributions 			}
3998*c54f35caSApple OSS Distributions 		}
3999*c54f35caSApple OSS Distributions 		iter->release();
4000*c54f35caSApple OSS Distributions 	}
4001*c54f35caSApple OSS Distributions 
4002*c54f35caSApple OSS Distributions 	if (children && (children->getCount() == 0)) {
4003*c54f35caSApple OSS Distributions 		children->release();
4004*c54f35caSApple OSS Distributions 		children = NULL;
4005*c54f35caSApple OSS Distributions 	}
4006*c54f35caSApple OSS Distributions 	if (children) {
4007*c54f35caSApple OSS Distributions 		assert(fNotifyChildArray == NULL);
4008*c54f35caSApple OSS Distributions 		fNotifyChildArray = children;
4009*c54f35caSApple OSS Distributions 		MS_PUSH(fMachineState);
4010*c54f35caSApple OSS Distributions 
4011*c54f35caSApple OSS Distributions 		if (delayNotify) {
4012*c54f35caSApple OSS Distributions 			// Block until all non-delayed children have acked their
4013*c54f35caSApple OSS Distributions 			// notification. Then notify the remaining delayed child
4014*c54f35caSApple OSS Distributions 			// in the array. This is used to hold off graphics child
4015*c54f35caSApple OSS Distributions 			// notification while the rest of the system powers up.
4016*c54f35caSApple OSS Distributions 			// If a hid tickle arrives during this time, the delayed
4017*c54f35caSApple OSS Distributions 			// children are immediately notified and root domain will
4018*c54f35caSApple OSS Distributions 			// not clamp power for dark wake.
4019*c54f35caSApple OSS Distributions 
4020*c54f35caSApple OSS Distributions 			fMachineState = kIOPM_NotifyChildrenDelayed;
4021*c54f35caSApple OSS Distributions 			PM_LOG2("%s: %d children in delayed array\n",
4022*c54f35caSApple OSS Distributions 			    getName(), children->getCount());
4023*c54f35caSApple OSS Distributions 		} else {
4024*c54f35caSApple OSS Distributions 			// Child array created to support strict notification order.
4025*c54f35caSApple OSS Distributions 			// Notify children in the array one at a time.
4026*c54f35caSApple OSS Distributions 
4027*c54f35caSApple OSS Distributions 			fMachineState = kIOPM_NotifyChildrenOrdered;
4028*c54f35caSApple OSS Distributions 		}
4029*c54f35caSApple OSS Distributions 	}
4030*c54f35caSApple OSS Distributions }
4031*c54f35caSApple OSS Distributions 
4032*c54f35caSApple OSS Distributions //*********************************************************************************
4033*c54f35caSApple OSS Distributions // [private] notifyChildrenOrdered
4034*c54f35caSApple OSS Distributions //*********************************************************************************
4035*c54f35caSApple OSS Distributions 
4036*c54f35caSApple OSS Distributions void
notifyChildrenOrdered(void)4037*c54f35caSApple OSS Distributions IOService::notifyChildrenOrdered( void )
4038*c54f35caSApple OSS Distributions {
4039*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4040*c54f35caSApple OSS Distributions 	assert(fNotifyChildArray);
4041*c54f35caSApple OSS Distributions 	assert(fMachineState == kIOPM_NotifyChildrenOrdered);
4042*c54f35caSApple OSS Distributions 
4043*c54f35caSApple OSS Distributions 	// Notify one child, wait for it to ack, then repeat for next child.
4044*c54f35caSApple OSS Distributions 	// This is a workaround for some drivers with multiple instances at
4045*c54f35caSApple OSS Distributions 	// the same branch in the power tree, but the driver is slow to power
4046*c54f35caSApple OSS Distributions 	// up unless the tree ordering is observed. Problem observed only on
4047*c54f35caSApple OSS Distributions 	// system wake, not on system sleep.
4048*c54f35caSApple OSS Distributions 	//
4049*c54f35caSApple OSS Distributions 	// We have the ability to power off in reverse child index order.
4050*c54f35caSApple OSS Distributions 	// That works nicely on some machines, but not on all HW configs.
4051*c54f35caSApple OSS Distributions 
4052*c54f35caSApple OSS Distributions 	if (fNotifyChildArray->getCount()) {
4053*c54f35caSApple OSS Distributions 		IOPowerConnection * connection;
4054*c54f35caSApple OSS Distributions 		connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
4055*c54f35caSApple OSS Distributions 		notifyChild( connection );
4056*c54f35caSApple OSS Distributions 		fNotifyChildArray->removeObject(0);
4057*c54f35caSApple OSS Distributions 	} else {
4058*c54f35caSApple OSS Distributions 		fNotifyChildArray->release();
4059*c54f35caSApple OSS Distributions 		fNotifyChildArray = NULL;
4060*c54f35caSApple OSS Distributions 
4061*c54f35caSApple OSS Distributions 		MS_POP(); // pushed by notifyChildren()
4062*c54f35caSApple OSS Distributions 	}
4063*c54f35caSApple OSS Distributions }
4064*c54f35caSApple OSS Distributions 
4065*c54f35caSApple OSS Distributions //*********************************************************************************
4066*c54f35caSApple OSS Distributions // [private] notifyChildrenDelayed
4067*c54f35caSApple OSS Distributions //*********************************************************************************
4068*c54f35caSApple OSS Distributions 
4069*c54f35caSApple OSS Distributions void
notifyChildrenDelayed(void)4070*c54f35caSApple OSS Distributions IOService::notifyChildrenDelayed( void )
4071*c54f35caSApple OSS Distributions {
4072*c54f35caSApple OSS Distributions 	IOPowerConnection * connection;
4073*c54f35caSApple OSS Distributions 
4074*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4075*c54f35caSApple OSS Distributions 	assert(fNotifyChildArray);
4076*c54f35caSApple OSS Distributions 	assert(fMachineState == kIOPM_NotifyChildrenDelayed);
4077*c54f35caSApple OSS Distributions 
4078*c54f35caSApple OSS Distributions 	// Wait after all non-delayed children and interested drivers have ack'ed,
4079*c54f35caSApple OSS Distributions 	// then notify all delayed children. If notify delay is canceled, child
4080*c54f35caSApple OSS Distributions 	// acks may be outstanding with PM blocked on fHeadNotePendingAcks != 0.
4081*c54f35caSApple OSS Distributions 	// But the handling for either case is identical.
4082*c54f35caSApple OSS Distributions 
4083*c54f35caSApple OSS Distributions 	for (int i = 0;; i++) {
4084*c54f35caSApple OSS Distributions 		connection = (IOPowerConnection *) fNotifyChildArray->getObject(i);
4085*c54f35caSApple OSS Distributions 		if (!connection) {
4086*c54f35caSApple OSS Distributions 			break;
4087*c54f35caSApple OSS Distributions 		}
4088*c54f35caSApple OSS Distributions 
4089*c54f35caSApple OSS Distributions 		notifyChild( connection );
4090*c54f35caSApple OSS Distributions 	}
4091*c54f35caSApple OSS Distributions 
4092*c54f35caSApple OSS Distributions 	PM_LOG2("%s: notified delayed children\n", getName());
4093*c54f35caSApple OSS Distributions 	fNotifyChildArray->release();
4094*c54f35caSApple OSS Distributions 	fNotifyChildArray = NULL;
4095*c54f35caSApple OSS Distributions 
4096*c54f35caSApple OSS Distributions 	MS_POP(); // pushed by notifyChildren()
4097*c54f35caSApple OSS Distributions }
4098*c54f35caSApple OSS Distributions 
4099*c54f35caSApple OSS Distributions //*********************************************************************************
4100*c54f35caSApple OSS Distributions // [private] notifyAll
4101*c54f35caSApple OSS Distributions //*********************************************************************************
4102*c54f35caSApple OSS Distributions 
4103*c54f35caSApple OSS Distributions IOReturn
notifyAll(uint32_t nextMS)4104*c54f35caSApple OSS Distributions IOService::notifyAll( uint32_t nextMS )
4105*c54f35caSApple OSS Distributions {
4106*c54f35caSApple OSS Distributions 	// Save the machine state to be restored by notifyInterestedDriversDone()
4107*c54f35caSApple OSS Distributions 
4108*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4109*c54f35caSApple OSS Distributions 	MS_PUSH(nextMS);
4110*c54f35caSApple OSS Distributions 	fMachineState     = kIOPM_DriverThreadCallDone;
4111*c54f35caSApple OSS Distributions 	fDriverCallReason = fIsPreChange ?
4112*c54f35caSApple OSS Distributions 	    kDriverCallInformPreChange : kDriverCallInformPostChange;
4113*c54f35caSApple OSS Distributions 
4114*c54f35caSApple OSS Distributions 	if (!notifyInterestedDrivers()) {
4115*c54f35caSApple OSS Distributions 		notifyInterestedDriversDone();
4116*c54f35caSApple OSS Distributions 	}
4117*c54f35caSApple OSS Distributions 
4118*c54f35caSApple OSS Distributions 	return IOPMWillAckLater;
4119*c54f35caSApple OSS Distributions }
4120*c54f35caSApple OSS Distributions 
4121*c54f35caSApple OSS Distributions //*********************************************************************************
4122*c54f35caSApple OSS Distributions // [private, static] pmDriverCallout
4123*c54f35caSApple OSS Distributions //
4124*c54f35caSApple OSS Distributions // Thread call context
4125*c54f35caSApple OSS Distributions //*********************************************************************************
4126*c54f35caSApple OSS Distributions 
4127*c54f35caSApple OSS Distributions IOReturn
actionDriverCalloutDone(OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)4128*c54f35caSApple OSS Distributions IOService::actionDriverCalloutDone(
4129*c54f35caSApple OSS Distributions 	OSObject * target,
4130*c54f35caSApple OSS Distributions 	void * arg0, void * arg1,
4131*c54f35caSApple OSS Distributions 	void * arg2, void * arg3 )
4132*c54f35caSApple OSS Distributions {
4133*c54f35caSApple OSS Distributions 	IOServicePM * pwrMgt = (IOServicePM *) arg0;
4134*c54f35caSApple OSS Distributions 
4135*c54f35caSApple OSS Distributions 	assert( fDriverCallBusy );
4136*c54f35caSApple OSS Distributions 	fDriverCallBusy = false;
4137*c54f35caSApple OSS Distributions 
4138*c54f35caSApple OSS Distributions 	assert(gIOPMWorkQueue);
4139*c54f35caSApple OSS Distributions 	gIOPMWorkQueue->signalWorkAvailable();
4140*c54f35caSApple OSS Distributions 
4141*c54f35caSApple OSS Distributions 	return kIOReturnSuccess;
4142*c54f35caSApple OSS Distributions }
4143*c54f35caSApple OSS Distributions 
4144*c54f35caSApple OSS Distributions void
pmDriverCallout(IOService * from,__unused thread_call_param_t p)4145*c54f35caSApple OSS Distributions IOService::pmDriverCallout( IOService * from,
4146*c54f35caSApple OSS Distributions     __unused thread_call_param_t p)
4147*c54f35caSApple OSS Distributions {
4148*c54f35caSApple OSS Distributions 	assert(from);
4149*c54f35caSApple OSS Distributions 	from->startDriverCalloutTimer();
4150*c54f35caSApple OSS Distributions 	switch (from->fDriverCallReason) {
4151*c54f35caSApple OSS Distributions 	case kDriverCallSetPowerState:
4152*c54f35caSApple OSS Distributions 		from->driverSetPowerState();
4153*c54f35caSApple OSS Distributions 		break;
4154*c54f35caSApple OSS Distributions 
4155*c54f35caSApple OSS Distributions 	case kDriverCallInformPreChange:
4156*c54f35caSApple OSS Distributions 	case kDriverCallInformPostChange:
4157*c54f35caSApple OSS Distributions 		from->driverInformPowerChange();
4158*c54f35caSApple OSS Distributions 		break;
4159*c54f35caSApple OSS Distributions 
4160*c54f35caSApple OSS Distributions 	case kRootDomainInformPreChange:
4161*c54f35caSApple OSS Distributions 		getPMRootDomain()->willNotifyPowerChildren(from->fHeadNotePowerState);
4162*c54f35caSApple OSS Distributions 		break;
4163*c54f35caSApple OSS Distributions 
4164*c54f35caSApple OSS Distributions 	default:
4165*c54f35caSApple OSS Distributions 		panic("IOService::pmDriverCallout bad machine state %x",
4166*c54f35caSApple OSS Distributions 		    from->fDriverCallReason);
4167*c54f35caSApple OSS Distributions 	}
4168*c54f35caSApple OSS Distributions 	from->stopDriverCalloutTimer();
4169*c54f35caSApple OSS Distributions 
4170*c54f35caSApple OSS Distributions 	gIOPMWorkLoop->runAction(actionDriverCalloutDone,
4171*c54f35caSApple OSS Distributions 	    /* target */ from,
4172*c54f35caSApple OSS Distributions 	    /* arg0   */ (void *) from->pwrMgt );
4173*c54f35caSApple OSS Distributions }
4174*c54f35caSApple OSS Distributions 
4175*c54f35caSApple OSS Distributions //*********************************************************************************
4176*c54f35caSApple OSS Distributions // [private] driverSetPowerState
4177*c54f35caSApple OSS Distributions //
4178*c54f35caSApple OSS Distributions // Thread call context
4179*c54f35caSApple OSS Distributions //*********************************************************************************
4180*c54f35caSApple OSS Distributions 
4181*c54f35caSApple OSS Distributions void
driverSetPowerState(void)4182*c54f35caSApple OSS Distributions IOService::driverSetPowerState( void )
4183*c54f35caSApple OSS Distributions {
4184*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex powerState;
4185*c54f35caSApple OSS Distributions 	DriverCallParam *   param;
4186*c54f35caSApple OSS Distributions 	IOPMDriverCallEntry callEntry;
4187*c54f35caSApple OSS Distributions 	AbsoluteTime        end;
4188*c54f35caSApple OSS Distributions 	IOReturn            result;
4189*c54f35caSApple OSS Distributions 	uint32_t            oldPowerState = getPowerState();
4190*c54f35caSApple OSS Distributions 	const OSMetaClass  *controllingDriverMetaClass = NULL;
4191*c54f35caSApple OSS Distributions 	uint32_t            controllingDriverRegistryEntryID = 0;
4192*c54f35caSApple OSS Distributions 
4193*c54f35caSApple OSS Distributions 	assert( fDriverCallBusy );
4194*c54f35caSApple OSS Distributions 	assert( fDriverCallParamPtr );
4195*c54f35caSApple OSS Distributions 	assert( fDriverCallParamCount == 1 );
4196*c54f35caSApple OSS Distributions 
4197*c54f35caSApple OSS Distributions 	param = (DriverCallParam *) fDriverCallParamPtr;
4198*c54f35caSApple OSS Distributions 	powerState = fHeadNotePowerState;
4199*c54f35caSApple OSS Distributions 	if (fControllingDriver) {
4200*c54f35caSApple OSS Distributions 		controllingDriverMetaClass = fControllingDriver->getMetaClass();
4201*c54f35caSApple OSS Distributions 		controllingDriverRegistryEntryID = (uint32_t)fControllingDriver->getRegistryEntryID();
4202*c54f35caSApple OSS Distributions 	}
4203*c54f35caSApple OSS Distributions 
4204*c54f35caSApple OSS Distributions 	if (assertPMDriverCall(&callEntry, kIOPMDriverCallMethodSetPowerState)) {
4205*c54f35caSApple OSS Distributions 		SOCD_TRACE_XNU_START(PM_SET_POWER_STATE,
4206*c54f35caSApple OSS Distributions 		    ADDR(controllingDriverMetaClass),
4207*c54f35caSApple OSS Distributions 		    ADDR(this->getMetaClass()),
4208*c54f35caSApple OSS Distributions 		    PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
4209*c54f35caSApple OSS Distributions 		    PACK_2X32(VALUE(powerState), VALUE(oldPowerState)));
4210*c54f35caSApple OSS Distributions 
4211*c54f35caSApple OSS Distributions 		OUR_PMLogFuncStart(kPMLogProgramHardware, (uintptr_t) this, powerState);
4212*c54f35caSApple OSS Distributions 		clock_get_uptime(&fDriverCallStartTime);
4213*c54f35caSApple OSS Distributions 
4214*c54f35caSApple OSS Distributions 		if (reserved && reserved->uvars && reserved->uvars->userServer) {
4215*c54f35caSApple OSS Distributions 			result = reserved->uvars->userServer->serviceSetPowerState(fControllingDriver, this, fHeadNotePowerArrayEntry->capabilityFlags, powerState);
4216*c54f35caSApple OSS Distributions 		} else {
4217*c54f35caSApple OSS Distributions 			result = fControllingDriver->setPowerState( powerState, this );
4218*c54f35caSApple OSS Distributions 		}
4219*c54f35caSApple OSS Distributions 		clock_get_uptime(&end);
4220*c54f35caSApple OSS Distributions 		OUR_PMLogFuncEnd(kPMLogProgramHardware, (uintptr_t) this, (UInt32) result);
4221*c54f35caSApple OSS Distributions 		SOCD_TRACE_XNU_END(PM_SET_POWER_STATE,
4222*c54f35caSApple OSS Distributions 		    ADDR(controllingDriverMetaClass),
4223*c54f35caSApple OSS Distributions 		    ADDR(this->getMetaClass()),
4224*c54f35caSApple OSS Distributions 		    PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
4225*c54f35caSApple OSS Distributions 		    PACK_2X32(VALUE(powerState), VALUE(result)));
4226*c54f35caSApple OSS Distributions 
4227*c54f35caSApple OSS Distributions 		deassertPMDriverCall(&callEntry);
4228*c54f35caSApple OSS Distributions 
4229*c54f35caSApple OSS Distributions 		// Record the most recent max power state residency timings.
4230*c54f35caSApple OSS Distributions 		// Use with DeviceActiveTimestamp to diagnose tickle issues.
4231*c54f35caSApple OSS Distributions 		if (powerState == fHighestPowerState) {
4232*c54f35caSApple OSS Distributions 			fMaxPowerStateEntryTime = end;
4233*c54f35caSApple OSS Distributions 		} else if (oldPowerState == fHighestPowerState) {
4234*c54f35caSApple OSS Distributions 			fMaxPowerStateExitTime = end;
4235*c54f35caSApple OSS Distributions 		}
4236*c54f35caSApple OSS Distributions 
4237*c54f35caSApple OSS Distributions 		if (result < 0) {
4238*c54f35caSApple OSS Distributions 			PM_LOG("%s::setPowerState(%p, %lu -> %lu) returned 0x%x\n",
4239*c54f35caSApple OSS Distributions 			    fName, OBFUSCATE(this), fCurrentPowerState, powerState, result);
4240*c54f35caSApple OSS Distributions 		}
4241*c54f35caSApple OSS Distributions 
4242*c54f35caSApple OSS Distributions 
4243*c54f35caSApple OSS Distributions 		if ((result == IOPMAckImplied) || (result < 0)) {
4244*c54f35caSApple OSS Distributions 			uint64_t    nsec;
4245*c54f35caSApple OSS Distributions 
4246*c54f35caSApple OSS Distributions 			SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
4247*c54f35caSApple OSS Distributions 			absolutetime_to_nanoseconds(end, &nsec);
4248*c54f35caSApple OSS Distributions 			if (nsec > gIOPMSetPowerStateLogNS) {
4249*c54f35caSApple OSS Distributions 				getPMRootDomain()->pmStatsRecordApplicationResponse(
4250*c54f35caSApple OSS Distributions 					gIOPMStatsDriverPSChangeSlow,
4251*c54f35caSApple OSS Distributions 					fName, kDriverCallSetPowerState, NS_TO_MS(nsec), getRegistryEntryID(),
4252*c54f35caSApple OSS Distributions 					NULL, powerState);
4253*c54f35caSApple OSS Distributions 			}
4254*c54f35caSApple OSS Distributions 		}
4255*c54f35caSApple OSS Distributions 	} else {
4256*c54f35caSApple OSS Distributions 		result = kIOPMAckImplied;
4257*c54f35caSApple OSS Distributions 	}
4258*c54f35caSApple OSS Distributions 
4259*c54f35caSApple OSS Distributions 	param->Result = result;
4260*c54f35caSApple OSS Distributions }
4261*c54f35caSApple OSS Distributions 
4262*c54f35caSApple OSS Distributions //*********************************************************************************
4263*c54f35caSApple OSS Distributions // [private] driverInformPowerChange
4264*c54f35caSApple OSS Distributions //
4265*c54f35caSApple OSS Distributions // Thread call context
4266*c54f35caSApple OSS Distributions //*********************************************************************************
4267*c54f35caSApple OSS Distributions 
4268*c54f35caSApple OSS Distributions void
driverInformPowerChange(void)4269*c54f35caSApple OSS Distributions IOService::driverInformPowerChange( void )
4270*c54f35caSApple OSS Distributions {
4271*c54f35caSApple OSS Distributions 	IOPMinformee *      informee;
4272*c54f35caSApple OSS Distributions 	IOService *         driver;
4273*c54f35caSApple OSS Distributions 	DriverCallParam *   param;
4274*c54f35caSApple OSS Distributions 	IOPMDriverCallEntry callEntry;
4275*c54f35caSApple OSS Distributions 	IOPMPowerFlags      powerFlags;
4276*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex powerState;
4277*c54f35caSApple OSS Distributions 	AbsoluteTime        end;
4278*c54f35caSApple OSS Distributions 	IOReturn            result;
4279*c54f35caSApple OSS Distributions 	IOItemCount         count;
4280*c54f35caSApple OSS Distributions 	IOOptionBits        callMethod = (fDriverCallReason == kDriverCallInformPreChange) ?
4281*c54f35caSApple OSS Distributions 	    kIOPMDriverCallMethodWillChange : kIOPMDriverCallMethodDidChange;
4282*c54f35caSApple OSS Distributions 
4283*c54f35caSApple OSS Distributions 	assert( fDriverCallBusy );
4284*c54f35caSApple OSS Distributions 	assert( fDriverCallParamPtr );
4285*c54f35caSApple OSS Distributions 	assert( fDriverCallParamCount );
4286*c54f35caSApple OSS Distributions 
4287*c54f35caSApple OSS Distributions 	param = (DriverCallParam *) fDriverCallParamPtr;
4288*c54f35caSApple OSS Distributions 	count = fDriverCallParamCount;
4289*c54f35caSApple OSS Distributions 
4290*c54f35caSApple OSS Distributions 	powerFlags = fHeadNotePowerArrayEntry->capabilityFlags;
4291*c54f35caSApple OSS Distributions 	powerState = fHeadNotePowerState;
4292*c54f35caSApple OSS Distributions 
4293*c54f35caSApple OSS Distributions 	for (IOItemCount i = 0; i < count; i++) {
4294*c54f35caSApple OSS Distributions 		informee = (IOPMinformee *) param->Target;
4295*c54f35caSApple OSS Distributions 		driver   = informee->whatObject;
4296*c54f35caSApple OSS Distributions 
4297*c54f35caSApple OSS Distributions 		if (assertPMDriverCall(&callEntry, callMethod, informee)) {
4298*c54f35caSApple OSS Distributions 			SOCD_TRACE_XNU_START(PM_INFORM_POWER_CHANGE,
4299*c54f35caSApple OSS Distributions 			    ADDR(driver->getMetaClass()),
4300*c54f35caSApple OSS Distributions 			    ADDR(this->getMetaClass()),
4301*c54f35caSApple OSS Distributions 			    PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(driver->getRegistryEntryID())),
4302*c54f35caSApple OSS Distributions 			    PACK_2X32(VALUE(powerState), VALUE(fDriverCallReason)));
4303*c54f35caSApple OSS Distributions 
4304*c54f35caSApple OSS Distributions 			if (fDriverCallReason == kDriverCallInformPreChange) {
4305*c54f35caSApple OSS Distributions 				OUR_PMLogFuncStart(kPMLogInformDriverPreChange, (uintptr_t) this, powerState);
4306*c54f35caSApple OSS Distributions 				clock_get_uptime(&informee->startTime);
4307*c54f35caSApple OSS Distributions 				result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
4308*c54f35caSApple OSS Distributions 				clock_get_uptime(&end);
4309*c54f35caSApple OSS Distributions 				OUR_PMLogFuncEnd(kPMLogInformDriverPreChange, (uintptr_t) this, result);
4310*c54f35caSApple OSS Distributions 			} else {
4311*c54f35caSApple OSS Distributions 				OUR_PMLogFuncStart(kPMLogInformDriverPostChange, (uintptr_t) this, powerState);
4312*c54f35caSApple OSS Distributions 				clock_get_uptime(&informee->startTime);
4313*c54f35caSApple OSS Distributions 				result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
4314*c54f35caSApple OSS Distributions 				clock_get_uptime(&end);
4315*c54f35caSApple OSS Distributions 				OUR_PMLogFuncEnd(kPMLogInformDriverPostChange, (uintptr_t) this, result);
4316*c54f35caSApple OSS Distributions 			}
4317*c54f35caSApple OSS Distributions 
4318*c54f35caSApple OSS Distributions 			SOCD_TRACE_XNU_END(PM_INFORM_POWER_CHANGE,
4319*c54f35caSApple OSS Distributions 			    ADDR(driver->getMetaClass()),
4320*c54f35caSApple OSS Distributions 			    ADDR(this->getMetaClass()),
4321*c54f35caSApple OSS Distributions 			    PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(driver->getRegistryEntryID())),
4322*c54f35caSApple OSS Distributions 			    PACK_2X32(VALUE(result), VALUE(fDriverCallReason)));
4323*c54f35caSApple OSS Distributions 
4324*c54f35caSApple OSS Distributions 			deassertPMDriverCall(&callEntry);
4325*c54f35caSApple OSS Distributions 
4326*c54f35caSApple OSS Distributions 
4327*c54f35caSApple OSS Distributions 			if ((result == IOPMAckImplied) || (result < 0)) {
4328*c54f35caSApple OSS Distributions 				uint64_t nsec;
4329*c54f35caSApple OSS Distributions 
4330*c54f35caSApple OSS Distributions 				SUB_ABSOLUTETIME(&end, &informee->startTime);
4331*c54f35caSApple OSS Distributions 				absolutetime_to_nanoseconds(end, &nsec);
4332*c54f35caSApple OSS Distributions 				if (nsec > gIOPMSetPowerStateLogNS) {
4333*c54f35caSApple OSS Distributions 					getPMRootDomain()->pmStatsRecordApplicationResponse(
4334*c54f35caSApple OSS Distributions 						gIOPMStatsDriverPSChangeSlow, driver->getName(),
4335*c54f35caSApple OSS Distributions 						fDriverCallReason, NS_TO_MS(nsec), driver->getRegistryEntryID(),
4336*c54f35caSApple OSS Distributions 						NULL, powerState);
4337*c54f35caSApple OSS Distributions 				}
4338*c54f35caSApple OSS Distributions 			}
4339*c54f35caSApple OSS Distributions 		} else {
4340*c54f35caSApple OSS Distributions 			result = kIOPMAckImplied;
4341*c54f35caSApple OSS Distributions 		}
4342*c54f35caSApple OSS Distributions 
4343*c54f35caSApple OSS Distributions 		param->Result = result;
4344*c54f35caSApple OSS Distributions 		param++;
4345*c54f35caSApple OSS Distributions 	}
4346*c54f35caSApple OSS Distributions }
4347*c54f35caSApple OSS Distributions 
4348*c54f35caSApple OSS Distributions //*********************************************************************************
4349*c54f35caSApple OSS Distributions // [private, static] pmDriverCalloutTimer
4350*c54f35caSApple OSS Distributions //
4351*c54f35caSApple OSS Distributions // Thread call context.
4352*c54f35caSApple OSS Distributions //*********************************************************************************
4353*c54f35caSApple OSS Distributions 
4354*c54f35caSApple OSS Distributions void
startDriverCalloutTimer(void)4355*c54f35caSApple OSS Distributions IOService::startDriverCalloutTimer( void )
4356*c54f35caSApple OSS Distributions {
4357*c54f35caSApple OSS Distributions 	AbsoluteTime    deadline;
4358*c54f35caSApple OSS Distributions 	boolean_t       pending;
4359*c54f35caSApple OSS Distributions 
4360*c54f35caSApple OSS Distributions 	clock_interval_to_deadline(gDriverCalloutTimer, kMillisecondScale, &deadline);
4361*c54f35caSApple OSS Distributions 
4362*c54f35caSApple OSS Distributions 	retain();
4363*c54f35caSApple OSS Distributions 	pending = thread_call_enter_delayed(fDriverCallTimer, deadline);
4364*c54f35caSApple OSS Distributions 	if (pending) {
4365*c54f35caSApple OSS Distributions 		release();
4366*c54f35caSApple OSS Distributions 	}
4367*c54f35caSApple OSS Distributions }
4368*c54f35caSApple OSS Distributions 
4369*c54f35caSApple OSS Distributions void
stopDriverCalloutTimer(void)4370*c54f35caSApple OSS Distributions IOService::stopDriverCalloutTimer( void )
4371*c54f35caSApple OSS Distributions {
4372*c54f35caSApple OSS Distributions 	boolean_t   pending;
4373*c54f35caSApple OSS Distributions 
4374*c54f35caSApple OSS Distributions 	pending = thread_call_cancel(fDriverCallTimer);
4375*c54f35caSApple OSS Distributions 	if (pending) {
4376*c54f35caSApple OSS Distributions 		release();
4377*c54f35caSApple OSS Distributions 	}
4378*c54f35caSApple OSS Distributions }
4379*c54f35caSApple OSS Distributions 
4380*c54f35caSApple OSS Distributions void
pmDriverCalloutTimer(thread_call_param_t arg0,__unused thread_call_param_t arg1)4381*c54f35caSApple OSS Distributions IOService::pmDriverCalloutTimer( thread_call_param_t arg0,
4382*c54f35caSApple OSS Distributions     __unused thread_call_param_t arg1)
4383*c54f35caSApple OSS Distributions {
4384*c54f35caSApple OSS Distributions 	assert(arg0);
4385*c54f35caSApple OSS Distributions 	IOService *from = (IOService *) arg0;
4386*c54f35caSApple OSS Distributions 	PM_LOG("PM waiting on pmDriverCallout(0x%x) to %s (%u ms)\n", from->fDriverCallReason, from->fName, gDriverCalloutTimer);
4387*c54f35caSApple OSS Distributions 	from->release();
4388*c54f35caSApple OSS Distributions }
4389*c54f35caSApple OSS Distributions 
4390*c54f35caSApple OSS Distributions //*********************************************************************************
4391*c54f35caSApple OSS Distributions // [private] notifyChild
4392*c54f35caSApple OSS Distributions //
4393*c54f35caSApple OSS Distributions // Notify a power domain child of an upcoming power change.
4394*c54f35caSApple OSS Distributions // If the object acknowledges the current change, we return TRUE.
4395*c54f35caSApple OSS Distributions //*********************************************************************************
4396*c54f35caSApple OSS Distributions 
4397*c54f35caSApple OSS Distributions bool
notifyChild(IOPowerConnection * theNub)4398*c54f35caSApple OSS Distributions IOService::notifyChild( IOPowerConnection * theNub )
4399*c54f35caSApple OSS Distributions {
4400*c54f35caSApple OSS Distributions 	IOReturn                ret = IOPMAckImplied;
4401*c54f35caSApple OSS Distributions 	unsigned long           childPower;
4402*c54f35caSApple OSS Distributions 	IOService *             theChild;
4403*c54f35caSApple OSS Distributions 	IOPMRequest *           childRequest;
4404*c54f35caSApple OSS Distributions 	IOPMPowerChangeFlags    requestArg2;
4405*c54f35caSApple OSS Distributions 	int                     requestType;
4406*c54f35caSApple OSS Distributions 
4407*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4408*c54f35caSApple OSS Distributions 	theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
4409*c54f35caSApple OSS Distributions 	if (!theChild) {
4410*c54f35caSApple OSS Distributions 		return true;
4411*c54f35caSApple OSS Distributions 	}
4412*c54f35caSApple OSS Distributions 
4413*c54f35caSApple OSS Distributions 	// Unless the child handles the notification immediately and returns
4414*c54f35caSApple OSS Distributions 	// kIOPMAckImplied, we'll be awaiting their acknowledgement later.
4415*c54f35caSApple OSS Distributions 	fHeadNotePendingAcks++;
4416*c54f35caSApple OSS Distributions 	theNub->setAwaitingAck(true);
4417*c54f35caSApple OSS Distributions 
4418*c54f35caSApple OSS Distributions 	requestArg2 = fHeadNoteChangeFlags;
4419*c54f35caSApple OSS Distributions 	if (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState)) {
4420*c54f35caSApple OSS Distributions 		requestArg2 |= kIOPMDomainPowerDrop;
4421*c54f35caSApple OSS Distributions 	}
4422*c54f35caSApple OSS Distributions 
4423*c54f35caSApple OSS Distributions 	requestType = fIsPreChange ?
4424*c54f35caSApple OSS Distributions 	    kIOPMRequestTypePowerDomainWillChange :
4425*c54f35caSApple OSS Distributions 	    kIOPMRequestTypePowerDomainDidChange;
4426*c54f35caSApple OSS Distributions 
4427*c54f35caSApple OSS Distributions 	childRequest = acquirePMRequest( theChild, requestType );
4428*c54f35caSApple OSS Distributions 	if (childRequest) {
4429*c54f35caSApple OSS Distributions 		theNub->retain();
4430*c54f35caSApple OSS Distributions 		childRequest->fArg0 = (void *) fHeadNotePowerArrayEntry->outputPowerFlags;
4431*c54f35caSApple OSS Distributions 		childRequest->fArg1 = (void *) theNub;
4432*c54f35caSApple OSS Distributions 		childRequest->fArg2 = (void *)(uintptr_t) requestArg2;
4433*c54f35caSApple OSS Distributions 		theChild->submitPMRequest( childRequest );
4434*c54f35caSApple OSS Distributions 		ret = IOPMWillAckLater;
4435*c54f35caSApple OSS Distributions 	} else {
4436*c54f35caSApple OSS Distributions 		ret = IOPMAckImplied;
4437*c54f35caSApple OSS Distributions 		fHeadNotePendingAcks--;
4438*c54f35caSApple OSS Distributions 		theNub->setAwaitingAck(false);
4439*c54f35caSApple OSS Distributions 		childPower = theChild->currentPowerConsumption();
4440*c54f35caSApple OSS Distributions 		if (childPower == kIOPMUnknown) {
4441*c54f35caSApple OSS Distributions 			fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
4442*c54f35caSApple OSS Distributions 		} else {
4443*c54f35caSApple OSS Distributions 			if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown) {
4444*c54f35caSApple OSS Distributions 				fHeadNotePowerArrayEntry->staticPower += childPower;
4445*c54f35caSApple OSS Distributions 			}
4446*c54f35caSApple OSS Distributions 		}
4447*c54f35caSApple OSS Distributions 	}
4448*c54f35caSApple OSS Distributions 
4449*c54f35caSApple OSS Distributions 	theChild->release();
4450*c54f35caSApple OSS Distributions 	return IOPMAckImplied == ret;
4451*c54f35caSApple OSS Distributions }
4452*c54f35caSApple OSS Distributions 
4453*c54f35caSApple OSS Distributions //*********************************************************************************
4454*c54f35caSApple OSS Distributions // [private] notifyControllingDriver
4455*c54f35caSApple OSS Distributions //*********************************************************************************
4456*c54f35caSApple OSS Distributions 
4457*c54f35caSApple OSS Distributions bool
notifyControllingDriver(void)4458*c54f35caSApple OSS Distributions IOService::notifyControllingDriver( void )
4459*c54f35caSApple OSS Distributions {
4460*c54f35caSApple OSS Distributions 	DriverCallParam *   param;
4461*c54f35caSApple OSS Distributions 
4462*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4463*c54f35caSApple OSS Distributions 	assert( fDriverCallParamCount == 0  );
4464*c54f35caSApple OSS Distributions 	assert( fControllingDriver );
4465*c54f35caSApple OSS Distributions 
4466*c54f35caSApple OSS Distributions 	if (fInitialSetPowerState) {
4467*c54f35caSApple OSS Distributions 		fInitialSetPowerState = false;
4468*c54f35caSApple OSS Distributions 		fHeadNoteChangeFlags |= kIOPMInitialPowerChange;
4469*c54f35caSApple OSS Distributions 
4470*c54f35caSApple OSS Distributions 		// Driver specified flag to skip the inital setPowerState()
4471*c54f35caSApple OSS Distributions 		if (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState) {
4472*c54f35caSApple OSS Distributions 			return false;
4473*c54f35caSApple OSS Distributions 		}
4474*c54f35caSApple OSS Distributions 	}
4475*c54f35caSApple OSS Distributions 
4476*c54f35caSApple OSS Distributions 	param = (DriverCallParam *) fDriverCallParamPtr;
4477*c54f35caSApple OSS Distributions 	if (!param) {
4478*c54f35caSApple OSS Distributions 		param = IONew(DriverCallParam, 1);
4479*c54f35caSApple OSS Distributions 		if (!param) {
4480*c54f35caSApple OSS Distributions 			return false; // no memory
4481*c54f35caSApple OSS Distributions 		}
4482*c54f35caSApple OSS Distributions 		fDriverCallParamPtr   = (void *) param;
4483*c54f35caSApple OSS Distributions 		fDriverCallParamSlots = 1;
4484*c54f35caSApple OSS Distributions 	}
4485*c54f35caSApple OSS Distributions 
4486*c54f35caSApple OSS Distributions 	param->Target = fControllingDriver;
4487*c54f35caSApple OSS Distributions 	fDriverCallParamCount = 1;
4488*c54f35caSApple OSS Distributions 	fDriverTimer = -1;
4489*c54f35caSApple OSS Distributions 
4490*c54f35caSApple OSS Distributions 	// Block state machine and wait for callout completion.
4491*c54f35caSApple OSS Distributions 	assert(!fDriverCallBusy);
4492*c54f35caSApple OSS Distributions 	fDriverCallBusy = true;
4493*c54f35caSApple OSS Distributions 	thread_call_enter( fDriverCallEntry );
4494*c54f35caSApple OSS Distributions 
4495*c54f35caSApple OSS Distributions 	return true;
4496*c54f35caSApple OSS Distributions }
4497*c54f35caSApple OSS Distributions 
4498*c54f35caSApple OSS Distributions //*********************************************************************************
4499*c54f35caSApple OSS Distributions // [private] notifyControllingDriverDone
4500*c54f35caSApple OSS Distributions //*********************************************************************************
4501*c54f35caSApple OSS Distributions 
4502*c54f35caSApple OSS Distributions void
notifyControllingDriverDone(void)4503*c54f35caSApple OSS Distributions IOService::notifyControllingDriverDone( void )
4504*c54f35caSApple OSS Distributions {
4505*c54f35caSApple OSS Distributions 	DriverCallParam *   param;
4506*c54f35caSApple OSS Distributions 	IOReturn            result;
4507*c54f35caSApple OSS Distributions 
4508*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4509*c54f35caSApple OSS Distributions 	param = (DriverCallParam *) fDriverCallParamPtr;
4510*c54f35caSApple OSS Distributions 
4511*c54f35caSApple OSS Distributions 	assert( fDriverCallBusy == false );
4512*c54f35caSApple OSS Distributions 	assert( fMachineState == kIOPM_DriverThreadCallDone );
4513*c54f35caSApple OSS Distributions 
4514*c54f35caSApple OSS Distributions 	if (param && fDriverCallParamCount) {
4515*c54f35caSApple OSS Distributions 		assert(fDriverCallParamCount == 1);
4516*c54f35caSApple OSS Distributions 
4517*c54f35caSApple OSS Distributions 		// the return value from setPowerState()
4518*c54f35caSApple OSS Distributions 		result = param->Result;
4519*c54f35caSApple OSS Distributions 
4520*c54f35caSApple OSS Distributions 		if ((result == IOPMAckImplied) || (result < 0)) {
4521*c54f35caSApple OSS Distributions 			fDriverTimer = 0;
4522*c54f35caSApple OSS Distributions 		} else if (fDriverTimer) {
4523*c54f35caSApple OSS Distributions 			assert(fDriverTimer == -1);
4524*c54f35caSApple OSS Distributions 
4525*c54f35caSApple OSS Distributions 			// Driver has not acked, and has returned a positive result.
4526*c54f35caSApple OSS Distributions 			// Enforce a minimum permissible timeout value.
4527*c54f35caSApple OSS Distributions 			// Make the min value large enough so timeout is less likely
4528*c54f35caSApple OSS Distributions 			// to occur if a driver misinterpreted that the return value
4529*c54f35caSApple OSS Distributions 			// should be in microsecond units.  And make it large enough
4530*c54f35caSApple OSS Distributions 			// to be noticeable if a driver neglects to ack.
4531*c54f35caSApple OSS Distributions 
4532*c54f35caSApple OSS Distributions 			if (result < kMinAckTimeoutTicks) {
4533*c54f35caSApple OSS Distributions 				result = kMinAckTimeoutTicks;
4534*c54f35caSApple OSS Distributions 			}
4535*c54f35caSApple OSS Distributions 
4536*c54f35caSApple OSS Distributions 			fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
4537*c54f35caSApple OSS Distributions 		}
4538*c54f35caSApple OSS Distributions 		// else, child has already acked and driver_timer reset to 0.
4539*c54f35caSApple OSS Distributions 
4540*c54f35caSApple OSS Distributions 		fDriverCallParamCount = 0;
4541*c54f35caSApple OSS Distributions 
4542*c54f35caSApple OSS Distributions 		if (fDriverTimer) {
4543*c54f35caSApple OSS Distributions 			OUR_PMLog(kPMLogStartAckTimer, 0, 0);
4544*c54f35caSApple OSS Distributions 			start_ack_timer();
4545*c54f35caSApple OSS Distributions 			getPMRootDomain()->reset_watchdog_timer(this, result / USEC_PER_SEC + 1);
4546*c54f35caSApple OSS Distributions 		}
4547*c54f35caSApple OSS Distributions 	}
4548*c54f35caSApple OSS Distributions 
4549*c54f35caSApple OSS Distributions 	MS_POP(); // pushed by OurChangeSetPowerState()
4550*c54f35caSApple OSS Distributions 	fIsPreChange  = false;
4551*c54f35caSApple OSS Distributions }
4552*c54f35caSApple OSS Distributions 
4553*c54f35caSApple OSS Distributions //*********************************************************************************
4554*c54f35caSApple OSS Distributions // [private] all_done
4555*c54f35caSApple OSS Distributions //
4556*c54f35caSApple OSS Distributions // A power change is done.
4557*c54f35caSApple OSS Distributions //*********************************************************************************
4558*c54f35caSApple OSS Distributions 
4559*c54f35caSApple OSS Distributions void
all_done(void)4560*c54f35caSApple OSS Distributions IOService::all_done( void )
4561*c54f35caSApple OSS Distributions {
4562*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex     prevPowerState;
4563*c54f35caSApple OSS Distributions 	const IOPMPSEntry *     powerStatePtr;
4564*c54f35caSApple OSS Distributions 	IOPMDriverCallEntry     callEntry;
4565*c54f35caSApple OSS Distributions 	uint32_t                prevMachineState = fMachineState;
4566*c54f35caSApple OSS Distributions 	bool                    actionCalled = false;
4567*c54f35caSApple OSS Distributions 	uint64_t                ts;
4568*c54f35caSApple OSS Distributions 
4569*c54f35caSApple OSS Distributions 	fMachineState = kIOPM_Finished;
4570*c54f35caSApple OSS Distributions 
4571*c54f35caSApple OSS Distributions 	if ((fHeadNoteChangeFlags & kIOPMSynchronize) &&
4572*c54f35caSApple OSS Distributions 	    ((prevMachineState == kIOPM_Finished) ||
4573*c54f35caSApple OSS Distributions 	    (prevMachineState == kIOPM_SyncFinish))) {
4574*c54f35caSApple OSS Distributions 		// Sync operation and no power change occurred.
4575*c54f35caSApple OSS Distributions 		// Do not inform driver and clients about this request completion,
4576*c54f35caSApple OSS Distributions 		// except for the originator (root domain).
4577*c54f35caSApple OSS Distributions 
4578*c54f35caSApple OSS Distributions 		PM_ACTION_CHANGE(actionPowerChangeDone,
4579*c54f35caSApple OSS Distributions 		    fHeadNotePowerState, fHeadNoteChangeFlags);
4580*c54f35caSApple OSS Distributions 
4581*c54f35caSApple OSS Distributions 		if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree) {
4582*c54f35caSApple OSS Distributions 			powerChangeDone(fCurrentPowerState);
4583*c54f35caSApple OSS Distributions 		} else if (fAdvisoryTickleUsed) {
4584*c54f35caSApple OSS Distributions 			// Not root domain and advisory tickle target.
4585*c54f35caSApple OSS Distributions 			// Re-adjust power after power tree sync at the 'did' pass
4586*c54f35caSApple OSS Distributions 			// to recompute desire and adjust power state between dark
4587*c54f35caSApple OSS Distributions 			// and full wake transitions. Root domain is responsible
4588*c54f35caSApple OSS Distributions 			// for calling setAdvisoryTickleEnable() before starting
4589*c54f35caSApple OSS Distributions 			// the kIOPMSynchronize power change.
4590*c54f35caSApple OSS Distributions 
4591*c54f35caSApple OSS Distributions 			if (!fAdjustPowerScheduled &&
4592*c54f35caSApple OSS Distributions 			    (fHeadNoteChangeFlags & kIOPMDomainDidChange)) {
4593*c54f35caSApple OSS Distributions 				IOPMRequest * request;
4594*c54f35caSApple OSS Distributions 				request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
4595*c54f35caSApple OSS Distributions 				if (request) {
4596*c54f35caSApple OSS Distributions 					submitPMRequest( request );
4597*c54f35caSApple OSS Distributions 					fAdjustPowerScheduled = true;
4598*c54f35caSApple OSS Distributions 				}
4599*c54f35caSApple OSS Distributions 			}
4600*c54f35caSApple OSS Distributions 		}
4601*c54f35caSApple OSS Distributions 
4602*c54f35caSApple OSS Distributions 		return;
4603*c54f35caSApple OSS Distributions 	}
4604*c54f35caSApple OSS Distributions 
4605*c54f35caSApple OSS Distributions 	// our power change
4606*c54f35caSApple OSS Distributions 	if (fHeadNoteChangeFlags & kIOPMSelfInitiated) {
4607*c54f35caSApple OSS Distributions 		// power state changed
4608*c54f35caSApple OSS Distributions 		if ((fHeadNoteChangeFlags & kIOPMNotDone) == 0) {
4609*c54f35caSApple OSS Distributions 			trackSystemSleepPreventers(
4610*c54f35caSApple OSS Distributions 				fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4611*c54f35caSApple OSS Distributions 
4612*c54f35caSApple OSS Distributions 			// we changed, tell our parent
4613*c54f35caSApple OSS Distributions 			requestDomainPower(fHeadNotePowerState);
4614*c54f35caSApple OSS Distributions 
4615*c54f35caSApple OSS Distributions 			// yes, did power raise?
4616*c54f35caSApple OSS Distributions 			if (StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState)) {
4617*c54f35caSApple OSS Distributions 				// yes, inform clients and apps
4618*c54f35caSApple OSS Distributions 				tellChangeUp(fHeadNotePowerState);
4619*c54f35caSApple OSS Distributions 			}
4620*c54f35caSApple OSS Distributions 			prevPowerState = fCurrentPowerState;
4621*c54f35caSApple OSS Distributions 			// either way
4622*c54f35caSApple OSS Distributions 			fCurrentPowerState = fHeadNotePowerState;
4623*c54f35caSApple OSS Distributions 			PM_LOCK();
4624*c54f35caSApple OSS Distributions 			if (fReportBuf) {
4625*c54f35caSApple OSS Distributions 				ts = mach_absolute_time();
4626*c54f35caSApple OSS Distributions 				STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
4627*c54f35caSApple OSS Distributions 			}
4628*c54f35caSApple OSS Distributions 			PM_UNLOCK();
4629*c54f35caSApple OSS Distributions #if PM_VARS_SUPPORT
4630*c54f35caSApple OSS Distributions 			fPMVars->myCurrentState = fCurrentPowerState;
4631*c54f35caSApple OSS Distributions #endif
4632*c54f35caSApple OSS Distributions 			OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4633*c54f35caSApple OSS Distributions 			PM_ACTION_CHANGE(actionPowerChangeDone,
4634*c54f35caSApple OSS Distributions 			    prevPowerState, fHeadNoteChangeFlags);
4635*c54f35caSApple OSS Distributions 			actionCalled = true;
4636*c54f35caSApple OSS Distributions 
4637*c54f35caSApple OSS Distributions 			powerStatePtr = &fPowerStates[fCurrentPowerState];
4638*c54f35caSApple OSS Distributions 			fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4639*c54f35caSApple OSS Distributions 			if (fCurrentCapabilityFlags & kIOPMStaticPowerValid) {
4640*c54f35caSApple OSS Distributions 				fCurrentPowerConsumption = powerStatePtr->staticPower;
4641*c54f35caSApple OSS Distributions 			}
4642*c54f35caSApple OSS Distributions 
4643*c54f35caSApple OSS Distributions 			if (fHeadNoteChangeFlags & kIOPMRootChangeDown) {
4644*c54f35caSApple OSS Distributions 				// Bump tickle generation count once the entire tree is down
4645*c54f35caSApple OSS Distributions 				gIOPMTickleGeneration++;
4646*c54f35caSApple OSS Distributions 			}
4647*c54f35caSApple OSS Distributions 
4648*c54f35caSApple OSS Distributions 			// inform subclass policy-maker
4649*c54f35caSApple OSS Distributions 			if (fPCDFunctionOverride && fParentsKnowState &&
4650*c54f35caSApple OSS Distributions 			    assertPMDriverCall(&callEntry, kIOPMDriverCallMethodChangeDone, NULL, kIOPMDriverCallNoInactiveCheck)) {
4651*c54f35caSApple OSS Distributions 				powerChangeDone(prevPowerState);
4652*c54f35caSApple OSS Distributions 				deassertPMDriverCall(&callEntry);
4653*c54f35caSApple OSS Distributions 			}
4654*c54f35caSApple OSS Distributions 		} else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride) {
4655*c54f35caSApple OSS Distributions 			// changePowerStateWithOverrideTo() was cancelled
4656*c54f35caSApple OSS Distributions 			fOverrideMaxPowerState = kIOPMPowerStateMax;
4657*c54f35caSApple OSS Distributions 		}
4658*c54f35caSApple OSS Distributions 	}
4659*c54f35caSApple OSS Distributions 
4660*c54f35caSApple OSS Distributions 	// parent-initiated power change
4661*c54f35caSApple OSS Distributions 	if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
4662*c54f35caSApple OSS Distributions 		if (fHeadNoteChangeFlags & kIOPMRootChangeDown) {
4663*c54f35caSApple OSS Distributions 			ParentChangeRootChangeDown();
4664*c54f35caSApple OSS Distributions 		}
4665*c54f35caSApple OSS Distributions 
4666*c54f35caSApple OSS Distributions 		// power state changed
4667*c54f35caSApple OSS Distributions 		if ((fHeadNoteChangeFlags & kIOPMNotDone) == 0) {
4668*c54f35caSApple OSS Distributions 			trackSystemSleepPreventers(
4669*c54f35caSApple OSS Distributions 				fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4670*c54f35caSApple OSS Distributions 
4671*c54f35caSApple OSS Distributions 			// did power raise?
4672*c54f35caSApple OSS Distributions 			if (StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState)) {
4673*c54f35caSApple OSS Distributions 				// yes, inform clients and apps
4674*c54f35caSApple OSS Distributions 				tellChangeUp(fHeadNotePowerState);
4675*c54f35caSApple OSS Distributions 			}
4676*c54f35caSApple OSS Distributions 			// either way
4677*c54f35caSApple OSS Distributions 			prevPowerState = fCurrentPowerState;
4678*c54f35caSApple OSS Distributions 			fCurrentPowerState = fHeadNotePowerState;
4679*c54f35caSApple OSS Distributions 			PM_LOCK();
4680*c54f35caSApple OSS Distributions 			if (fReportBuf) {
4681*c54f35caSApple OSS Distributions 				ts = mach_absolute_time();
4682*c54f35caSApple OSS Distributions 				STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
4683*c54f35caSApple OSS Distributions 			}
4684*c54f35caSApple OSS Distributions 			PM_UNLOCK();
4685*c54f35caSApple OSS Distributions #if PM_VARS_SUPPORT
4686*c54f35caSApple OSS Distributions 			fPMVars->myCurrentState = fCurrentPowerState;
4687*c54f35caSApple OSS Distributions #endif
4688*c54f35caSApple OSS Distributions 
4689*c54f35caSApple OSS Distributions 			OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4690*c54f35caSApple OSS Distributions 			PM_ACTION_CHANGE(actionPowerChangeDone,
4691*c54f35caSApple OSS Distributions 			    prevPowerState, fHeadNoteChangeFlags);
4692*c54f35caSApple OSS Distributions 			actionCalled = true;
4693*c54f35caSApple OSS Distributions 
4694*c54f35caSApple OSS Distributions 			powerStatePtr = &fPowerStates[fCurrentPowerState];
4695*c54f35caSApple OSS Distributions 			fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4696*c54f35caSApple OSS Distributions 			if (fCurrentCapabilityFlags & kIOPMStaticPowerValid) {
4697*c54f35caSApple OSS Distributions 				fCurrentPowerConsumption = powerStatePtr->staticPower;
4698*c54f35caSApple OSS Distributions 			}
4699*c54f35caSApple OSS Distributions 
4700*c54f35caSApple OSS Distributions 			// inform subclass policy-maker
4701*c54f35caSApple OSS Distributions 			if (fPCDFunctionOverride && fParentsKnowState &&
4702*c54f35caSApple OSS Distributions 			    assertPMDriverCall(&callEntry, kIOPMDriverCallMethodChangeDone, NULL, kIOPMDriverCallNoInactiveCheck)) {
4703*c54f35caSApple OSS Distributions 				powerChangeDone(prevPowerState);
4704*c54f35caSApple OSS Distributions 				deassertPMDriverCall(&callEntry);
4705*c54f35caSApple OSS Distributions 			}
4706*c54f35caSApple OSS Distributions 		}
4707*c54f35caSApple OSS Distributions 	}
4708*c54f35caSApple OSS Distributions 
4709*c54f35caSApple OSS Distributions 	// When power rises enough to satisfy the tickle's desire for more power,
4710*c54f35caSApple OSS Distributions 	// the condition preventing idle-timer from dropping power is removed.
4711*c54f35caSApple OSS Distributions 
4712*c54f35caSApple OSS Distributions 	if (StateOrder(fCurrentPowerState) >= StateOrder(fIdleTimerMinPowerState)) {
4713*c54f35caSApple OSS Distributions 		fIdleTimerMinPowerState = kPowerStateZero;
4714*c54f35caSApple OSS Distributions 	}
4715*c54f35caSApple OSS Distributions 
4716*c54f35caSApple OSS Distributions 	if (!actionCalled) {
4717*c54f35caSApple OSS Distributions 		PM_ACTION_CHANGE(actionPowerChangeDone,
4718*c54f35caSApple OSS Distributions 		    fHeadNotePowerState, fHeadNoteChangeFlags);
4719*c54f35caSApple OSS Distributions 	}
4720*c54f35caSApple OSS Distributions }
4721*c54f35caSApple OSS Distributions 
4722*c54f35caSApple OSS Distributions // MARK: -
4723*c54f35caSApple OSS Distributions // MARK: Power Change Initiated by Driver
4724*c54f35caSApple OSS Distributions 
4725*c54f35caSApple OSS Distributions //*********************************************************************************
4726*c54f35caSApple OSS Distributions // [private] OurChangeStart
4727*c54f35caSApple OSS Distributions //
4728*c54f35caSApple OSS Distributions // Begin the processing of a power change initiated by us.
4729*c54f35caSApple OSS Distributions //*********************************************************************************
4730*c54f35caSApple OSS Distributions 
4731*c54f35caSApple OSS Distributions void
OurChangeStart(void)4732*c54f35caSApple OSS Distributions IOService::OurChangeStart( void )
4733*c54f35caSApple OSS Distributions {
4734*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4735*c54f35caSApple OSS Distributions 	OUR_PMLog( kPMLogStartDeviceChange, fHeadNotePowerState, fCurrentPowerState );
4736*c54f35caSApple OSS Distributions 
4737*c54f35caSApple OSS Distributions 	// fMaxPowerState is our maximum possible power state based on the current
4738*c54f35caSApple OSS Distributions 	// power state of our parents.  If we are trying to raise power beyond the
4739*c54f35caSApple OSS Distributions 	// maximum, send an async request for more power to all parents.
4740*c54f35caSApple OSS Distributions 
4741*c54f35caSApple OSS Distributions 	if (!IS_PM_ROOT && (StateOrder(fMaxPowerState) < StateOrder(fHeadNotePowerState))) {
4742*c54f35caSApple OSS Distributions 		fHeadNoteChangeFlags |= kIOPMNotDone;
4743*c54f35caSApple OSS Distributions 		requestDomainPower(fHeadNotePowerState);
4744*c54f35caSApple OSS Distributions 		OurChangeFinish();
4745*c54f35caSApple OSS Distributions 		return;
4746*c54f35caSApple OSS Distributions 	}
4747*c54f35caSApple OSS Distributions 
4748*c54f35caSApple OSS Distributions 	// Redundant power changes skips to the end of the state machine.
4749*c54f35caSApple OSS Distributions 
4750*c54f35caSApple OSS Distributions 	if (!fInitialPowerChange && (fHeadNotePowerState == fCurrentPowerState)) {
4751*c54f35caSApple OSS Distributions 		OurChangeFinish();
4752*c54f35caSApple OSS Distributions 		return;
4753*c54f35caSApple OSS Distributions 	}
4754*c54f35caSApple OSS Distributions 	fInitialPowerChange = false;
4755*c54f35caSApple OSS Distributions 
4756*c54f35caSApple OSS Distributions 	// Change started, but may not complete...
4757*c54f35caSApple OSS Distributions 	// Can be canceled (power drop) or deferred (power rise).
4758*c54f35caSApple OSS Distributions 
4759*c54f35caSApple OSS Distributions 	PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4760*c54f35caSApple OSS Distributions 
4761*c54f35caSApple OSS Distributions 	// Two separate paths, depending if power is being raised or lowered.
4762*c54f35caSApple OSS Distributions 	// Lowering power is subject to approval by clients of this service.
4763*c54f35caSApple OSS Distributions 
4764*c54f35caSApple OSS Distributions 	if (IS_POWER_DROP) {
4765*c54f35caSApple OSS Distributions 		fDoNotPowerDown = false;
4766*c54f35caSApple OSS Distributions 
4767*c54f35caSApple OSS Distributions 		// Ask for persmission to drop power state
4768*c54f35caSApple OSS Distributions 		fMachineState = kIOPM_OurChangeTellClientsPowerDown;
4769*c54f35caSApple OSS Distributions 		fOutOfBandParameter = kNotifyApps;
4770*c54f35caSApple OSS Distributions 		askChangeDown(fHeadNotePowerState);
4771*c54f35caSApple OSS Distributions 	} else {
4772*c54f35caSApple OSS Distributions 		// This service is raising power and parents are able to support the
4773*c54f35caSApple OSS Distributions 		// new power state. However a parent may have already committed to
4774*c54f35caSApple OSS Distributions 		// drop power, which might force this object to temporarily drop power.
4775*c54f35caSApple OSS Distributions 		// This results in "oscillations" before the state machines converge
4776*c54f35caSApple OSS Distributions 		// to a steady state.
4777*c54f35caSApple OSS Distributions 		//
4778*c54f35caSApple OSS Distributions 		// To prevent this, a child must make a power reservation against all
4779*c54f35caSApple OSS Distributions 		// parents before raising power. If the reservation fails, indicating
4780*c54f35caSApple OSS Distributions 		// that the child will be unable to sustain the higher power state,
4781*c54f35caSApple OSS Distributions 		// then the child will signal the parent to adjust power, and the child
4782*c54f35caSApple OSS Distributions 		// will defer its power change.
4783*c54f35caSApple OSS Distributions 
4784*c54f35caSApple OSS Distributions 		IOReturn ret;
4785*c54f35caSApple OSS Distributions 
4786*c54f35caSApple OSS Distributions 		// Reserve parent power necessary to achieve fHeadNotePowerState.
4787*c54f35caSApple OSS Distributions 		ret = requestDomainPower( fHeadNotePowerState, kReserveDomainPower );
4788*c54f35caSApple OSS Distributions 		if (ret != kIOReturnSuccess) {
4789*c54f35caSApple OSS Distributions 			// Reservation failed, defer power rise.
4790*c54f35caSApple OSS Distributions 			fHeadNoteChangeFlags |= kIOPMNotDone;
4791*c54f35caSApple OSS Distributions 			OurChangeFinish();
4792*c54f35caSApple OSS Distributions 			return;
4793*c54f35caSApple OSS Distributions 		}
4794*c54f35caSApple OSS Distributions 
4795*c54f35caSApple OSS Distributions 		OurChangeTellCapabilityWillChange();
4796*c54f35caSApple OSS Distributions 	}
4797*c54f35caSApple OSS Distributions }
4798*c54f35caSApple OSS Distributions 
4799*c54f35caSApple OSS Distributions //*********************************************************************************
4800*c54f35caSApple OSS Distributions // [private] requestDomainPowerApplier
4801*c54f35caSApple OSS Distributions //
4802*c54f35caSApple OSS Distributions // Call requestPowerDomainState() on all power parents.
4803*c54f35caSApple OSS Distributions //*********************************************************************************
4804*c54f35caSApple OSS Distributions 
4805*c54f35caSApple OSS Distributions struct IOPMRequestDomainPowerContext {
4806*c54f35caSApple OSS Distributions 	IOService *     child;          // the requesting child
4807*c54f35caSApple OSS Distributions 	IOPMPowerFlags  requestPowerFlags;// power flags requested by child
4808*c54f35caSApple OSS Distributions };
4809*c54f35caSApple OSS Distributions 
4810*c54f35caSApple OSS Distributions static void
requestDomainPowerApplier(IORegistryEntry * entry,void * inContext)4811*c54f35caSApple OSS Distributions requestDomainPowerApplier(
4812*c54f35caSApple OSS Distributions 	IORegistryEntry *   entry,
4813*c54f35caSApple OSS Distributions 	void *              inContext )
4814*c54f35caSApple OSS Distributions {
4815*c54f35caSApple OSS Distributions 	IOPowerConnection *             connection;
4816*c54f35caSApple OSS Distributions 	IOService *                     parent;
4817*c54f35caSApple OSS Distributions 	IOPMRequestDomainPowerContext * context;
4818*c54f35caSApple OSS Distributions 
4819*c54f35caSApple OSS Distributions 	if ((connection = OSDynamicCast(IOPowerConnection, entry)) == NULL) {
4820*c54f35caSApple OSS Distributions 		return;
4821*c54f35caSApple OSS Distributions 	}
4822*c54f35caSApple OSS Distributions 	parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
4823*c54f35caSApple OSS Distributions 	if (!parent) {
4824*c54f35caSApple OSS Distributions 		return;
4825*c54f35caSApple OSS Distributions 	}
4826*c54f35caSApple OSS Distributions 
4827*c54f35caSApple OSS Distributions 	assert(inContext);
4828*c54f35caSApple OSS Distributions 	context = (IOPMRequestDomainPowerContext *) inContext;
4829*c54f35caSApple OSS Distributions 
4830*c54f35caSApple OSS Distributions 	if (connection->parentKnowsState() && connection->getReadyFlag()) {
4831*c54f35caSApple OSS Distributions 		parent->requestPowerDomainState(
4832*c54f35caSApple OSS Distributions 			context->requestPowerFlags,
4833*c54f35caSApple OSS Distributions 			connection,
4834*c54f35caSApple OSS Distributions 			IOPMLowestState);
4835*c54f35caSApple OSS Distributions 	}
4836*c54f35caSApple OSS Distributions 
4837*c54f35caSApple OSS Distributions 	parent->release();
4838*c54f35caSApple OSS Distributions }
4839*c54f35caSApple OSS Distributions 
4840*c54f35caSApple OSS Distributions //*********************************************************************************
4841*c54f35caSApple OSS Distributions // [private] requestDomainPower
4842*c54f35caSApple OSS Distributions //
4843*c54f35caSApple OSS Distributions // Called by a power child to broadcast its desired power state to all parents.
4844*c54f35caSApple OSS Distributions // If the child self-initiates a power change, it must call this function to
4845*c54f35caSApple OSS Distributions // allow its parents to adjust power state.
4846*c54f35caSApple OSS Distributions //*********************************************************************************
4847*c54f35caSApple OSS Distributions 
4848*c54f35caSApple OSS Distributions IOReturn
requestDomainPower(IOPMPowerStateIndex ourPowerState,IOOptionBits options)4849*c54f35caSApple OSS Distributions IOService::requestDomainPower(
4850*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex ourPowerState,
4851*c54f35caSApple OSS Distributions 	IOOptionBits        options )
4852*c54f35caSApple OSS Distributions {
4853*c54f35caSApple OSS Distributions 	IOPMPowerFlags                  requestPowerFlags;
4854*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex             maxPowerState;
4855*c54f35caSApple OSS Distributions 	IOPMRequestDomainPowerContext   context;
4856*c54f35caSApple OSS Distributions 
4857*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4858*c54f35caSApple OSS Distributions 	assert(ourPowerState < fNumberOfPowerStates);
4859*c54f35caSApple OSS Distributions 	if (ourPowerState >= fNumberOfPowerStates) {
4860*c54f35caSApple OSS Distributions 		return kIOReturnBadArgument;
4861*c54f35caSApple OSS Distributions 	}
4862*c54f35caSApple OSS Distributions 	if (IS_PM_ROOT) {
4863*c54f35caSApple OSS Distributions 		return kIOReturnSuccess;
4864*c54f35caSApple OSS Distributions 	}
4865*c54f35caSApple OSS Distributions 
4866*c54f35caSApple OSS Distributions 	// Fetch our input power flags for the requested power state.
4867*c54f35caSApple OSS Distributions 	// Parent request is stated in terms of required power flags.
4868*c54f35caSApple OSS Distributions 
4869*c54f35caSApple OSS Distributions 	requestPowerFlags = fPowerStates[ourPowerState].inputPowerFlags;
4870*c54f35caSApple OSS Distributions 
4871*c54f35caSApple OSS Distributions 	// Disregard the "previous request" for power reservation.
4872*c54f35caSApple OSS Distributions 
4873*c54f35caSApple OSS Distributions 	if (((options & kReserveDomainPower) == 0) &&
4874*c54f35caSApple OSS Distributions 	    (fPreviousRequestPowerFlags == requestPowerFlags)) {
4875*c54f35caSApple OSS Distributions 		// skip if domain already knows our requirements
4876*c54f35caSApple OSS Distributions 		goto done;
4877*c54f35caSApple OSS Distributions 	}
4878*c54f35caSApple OSS Distributions 	fPreviousRequestPowerFlags = requestPowerFlags;
4879*c54f35caSApple OSS Distributions 
4880*c54f35caSApple OSS Distributions 	// The results will be collected by fHeadNoteDomainTargetFlags
4881*c54f35caSApple OSS Distributions 	context.child              = this;
4882*c54f35caSApple OSS Distributions 	context.requestPowerFlags  = requestPowerFlags;
4883*c54f35caSApple OSS Distributions 	fHeadNoteDomainTargetFlags = 0;
4884*c54f35caSApple OSS Distributions 	applyToParents(requestDomainPowerApplier, &context, gIOPowerPlane);
4885*c54f35caSApple OSS Distributions 
4886*c54f35caSApple OSS Distributions 	if (options & kReserveDomainPower) {
4887*c54f35caSApple OSS Distributions 		maxPowerState = fControllingDriver->maxCapabilityForDomainState(
4888*c54f35caSApple OSS Distributions 			fHeadNoteDomainTargetFlags );
4889*c54f35caSApple OSS Distributions 
4890*c54f35caSApple OSS Distributions 		if (StateOrder(maxPowerState) < StateOrder(ourPowerState)) {
4891*c54f35caSApple OSS Distributions 			PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
4892*c54f35caSApple OSS Distributions 			    getName(),
4893*c54f35caSApple OSS Distributions 			    (uint32_t) ourPowerState, (uint32_t) requestPowerFlags,
4894*c54f35caSApple OSS Distributions 			    (uint32_t) maxPowerState, (uint32_t) fHeadNoteDomainTargetFlags);
4895*c54f35caSApple OSS Distributions 			return kIOReturnNoPower;
4896*c54f35caSApple OSS Distributions 		}
4897*c54f35caSApple OSS Distributions 	}
4898*c54f35caSApple OSS Distributions 
4899*c54f35caSApple OSS Distributions done:
4900*c54f35caSApple OSS Distributions 	return kIOReturnSuccess;
4901*c54f35caSApple OSS Distributions }
4902*c54f35caSApple OSS Distributions 
4903*c54f35caSApple OSS Distributions //*********************************************************************************
4904*c54f35caSApple OSS Distributions // [private] OurSyncStart
4905*c54f35caSApple OSS Distributions //*********************************************************************************
4906*c54f35caSApple OSS Distributions 
4907*c54f35caSApple OSS Distributions void
OurSyncStart(void)4908*c54f35caSApple OSS Distributions IOService::OurSyncStart( void )
4909*c54f35caSApple OSS Distributions {
4910*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
4911*c54f35caSApple OSS Distributions 
4912*c54f35caSApple OSS Distributions 	if (fInitialPowerChange) {
4913*c54f35caSApple OSS Distributions 		return;
4914*c54f35caSApple OSS Distributions 	}
4915*c54f35caSApple OSS Distributions 
4916*c54f35caSApple OSS Distributions 	PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4917*c54f35caSApple OSS Distributions 
4918*c54f35caSApple OSS Distributions 	if (fHeadNoteChangeFlags & kIOPMNotDone) {
4919*c54f35caSApple OSS Distributions 		OurChangeFinish();
4920*c54f35caSApple OSS Distributions 		return;
4921*c54f35caSApple OSS Distributions 	}
4922*c54f35caSApple OSS Distributions 
4923*c54f35caSApple OSS Distributions 	if (fHeadNoteChangeFlags & kIOPMSyncTellPowerDown) {
4924*c54f35caSApple OSS Distributions 		fDoNotPowerDown = false;
4925*c54f35caSApple OSS Distributions 
4926*c54f35caSApple OSS Distributions 		// Ask for permission to drop power state
4927*c54f35caSApple OSS Distributions 		fMachineState = kIOPM_SyncTellClientsPowerDown;
4928*c54f35caSApple OSS Distributions 		fOutOfBandParameter = kNotifyApps;
4929*c54f35caSApple OSS Distributions 		askChangeDown(fHeadNotePowerState);
4930*c54f35caSApple OSS Distributions 	} else {
4931*c54f35caSApple OSS Distributions 		// Only inform capability app and clients.
4932*c54f35caSApple OSS Distributions 		tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange );
4933*c54f35caSApple OSS Distributions 	}
4934*c54f35caSApple OSS Distributions }
4935*c54f35caSApple OSS Distributions 
4936*c54f35caSApple OSS Distributions //*********************************************************************************
4937*c54f35caSApple OSS Distributions // [private] OurChangeTellClientsPowerDown
4938*c54f35caSApple OSS Distributions //
4939*c54f35caSApple OSS Distributions // All applications and kernel clients have acknowledged our permission to drop
4940*c54f35caSApple OSS Distributions // power. Here we notify them that we will lower the power and wait for acks.
4941*c54f35caSApple OSS Distributions //*********************************************************************************
4942*c54f35caSApple OSS Distributions 
4943*c54f35caSApple OSS Distributions void
OurChangeTellClientsPowerDown(void)4944*c54f35caSApple OSS Distributions IOService::OurChangeTellClientsPowerDown( void )
4945*c54f35caSApple OSS Distributions {
4946*c54f35caSApple OSS Distributions 	if (!IS_ROOT_DOMAIN) {
4947*c54f35caSApple OSS Distributions 		fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4948*c54f35caSApple OSS Distributions 	} else {
4949*c54f35caSApple OSS Distributions 		fMachineState = kIOPM_OurChangeTellUserPMPolicyPowerDown;
4950*c54f35caSApple OSS Distributions 	}
4951*c54f35caSApple OSS Distributions 	tellChangeDown1(fHeadNotePowerState);
4952*c54f35caSApple OSS Distributions }
4953*c54f35caSApple OSS Distributions 
4954*c54f35caSApple OSS Distributions //*********************************************************************************
4955*c54f35caSApple OSS Distributions // [private] OurChangeTellUserPMPolicyPowerDown
4956*c54f35caSApple OSS Distributions //
4957*c54f35caSApple OSS Distributions // All applications and kernel clients have acknowledged our permission to drop
4958*c54f35caSApple OSS Distributions // power. Here we notify power management policy in user-space and wait for acks
4959*c54f35caSApple OSS Distributions // one last time before we lower power
4960*c54f35caSApple OSS Distributions //*********************************************************************************
4961*c54f35caSApple OSS Distributions void
OurChangeTellUserPMPolicyPowerDown(void)4962*c54f35caSApple OSS Distributions IOService::OurChangeTellUserPMPolicyPowerDown( void )
4963*c54f35caSApple OSS Distributions {
4964*c54f35caSApple OSS Distributions 	fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4965*c54f35caSApple OSS Distributions 	fOutOfBandParameter = kNotifyApps;
4966*c54f35caSApple OSS Distributions 
4967*c54f35caSApple OSS Distributions 	tellClientsWithResponse(kIOPMMessageLastCallBeforeSleep);
4968*c54f35caSApple OSS Distributions }
4969*c54f35caSApple OSS Distributions 
4970*c54f35caSApple OSS Distributions //*********************************************************************************
4971*c54f35caSApple OSS Distributions // [private] OurChangeTellPriorityClientsPowerDown
4972*c54f35caSApple OSS Distributions //
4973*c54f35caSApple OSS Distributions // All applications and kernel clients have acknowledged our intention to drop
4974*c54f35caSApple OSS Distributions // power.  Here we notify "priority" clients that we are lowering power.
4975*c54f35caSApple OSS Distributions //*********************************************************************************
4976*c54f35caSApple OSS Distributions 
4977*c54f35caSApple OSS Distributions void
OurChangeTellPriorityClientsPowerDown(void)4978*c54f35caSApple OSS Distributions IOService::OurChangeTellPriorityClientsPowerDown( void )
4979*c54f35caSApple OSS Distributions {
4980*c54f35caSApple OSS Distributions 	fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
4981*c54f35caSApple OSS Distributions 	tellChangeDown2(fHeadNotePowerState);
4982*c54f35caSApple OSS Distributions }
4983*c54f35caSApple OSS Distributions 
4984*c54f35caSApple OSS Distributions //*********************************************************************************
4985*c54f35caSApple OSS Distributions // [private] OurChangeTellCapabilityWillChange
4986*c54f35caSApple OSS Distributions //
4987*c54f35caSApple OSS Distributions // Extra stage for root domain to notify apps and drivers about the
4988*c54f35caSApple OSS Distributions // system capability change when raising power state.
4989*c54f35caSApple OSS Distributions //*********************************************************************************
4990*c54f35caSApple OSS Distributions 
4991*c54f35caSApple OSS Distributions void
OurChangeTellCapabilityWillChange(void)4992*c54f35caSApple OSS Distributions IOService::OurChangeTellCapabilityWillChange( void )
4993*c54f35caSApple OSS Distributions {
4994*c54f35caSApple OSS Distributions 	if (!IS_ROOT_DOMAIN) {
4995*c54f35caSApple OSS Distributions 		return OurChangeNotifyInterestedDriversWillChange();
4996*c54f35caSApple OSS Distributions 	}
4997*c54f35caSApple OSS Distributions 
4998*c54f35caSApple OSS Distributions 	tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange );
4999*c54f35caSApple OSS Distributions }
5000*c54f35caSApple OSS Distributions 
5001*c54f35caSApple OSS Distributions //*********************************************************************************
5002*c54f35caSApple OSS Distributions // [private] OurChangeNotifyInterestedDriversWillChange
5003*c54f35caSApple OSS Distributions //
5004*c54f35caSApple OSS Distributions // All applications and kernel clients have acknowledged our power state change.
5005*c54f35caSApple OSS Distributions // Here we notify interested drivers pre-change.
5006*c54f35caSApple OSS Distributions //*********************************************************************************
5007*c54f35caSApple OSS Distributions 
5008*c54f35caSApple OSS Distributions void
OurChangeNotifyInterestedDriversWillChange(void)5009*c54f35caSApple OSS Distributions IOService::OurChangeNotifyInterestedDriversWillChange( void )
5010*c54f35caSApple OSS Distributions {
5011*c54f35caSApple OSS Distributions 	IOPMrootDomain * rootDomain;
5012*c54f35caSApple OSS Distributions 	if ((rootDomain = getPMRootDomain()) == this) {
5013*c54f35caSApple OSS Distributions 		if (IS_POWER_DROP) {
5014*c54f35caSApple OSS Distributions 			rootDomain->tracePoint( kIOPMTracePointSleepWillChangeInterests );
5015*c54f35caSApple OSS Distributions 		} else {
5016*c54f35caSApple OSS Distributions 			rootDomain->tracePoint( kIOPMTracePointWakeWillChangeInterests );
5017*c54f35caSApple OSS Distributions 		}
5018*c54f35caSApple OSS Distributions 	}
5019*c54f35caSApple OSS Distributions 
5020*c54f35caSApple OSS Distributions 	notifyAll( kIOPM_OurChangeSetPowerState );
5021*c54f35caSApple OSS Distributions }
5022*c54f35caSApple OSS Distributions 
5023*c54f35caSApple OSS Distributions //*********************************************************************************
5024*c54f35caSApple OSS Distributions // [private] OurChangeSetPowerState
5025*c54f35caSApple OSS Distributions //
5026*c54f35caSApple OSS Distributions // Instruct our controlling driver to program the hardware for the power state
5027*c54f35caSApple OSS Distributions // change. Wait for async completions.
5028*c54f35caSApple OSS Distributions //*********************************************************************************
5029*c54f35caSApple OSS Distributions 
5030*c54f35caSApple OSS Distributions void
OurChangeSetPowerState(void)5031*c54f35caSApple OSS Distributions IOService::OurChangeSetPowerState( void )
5032*c54f35caSApple OSS Distributions {
5033*c54f35caSApple OSS Distributions 	MS_PUSH( kIOPM_OurChangeWaitForPowerSettle );
5034*c54f35caSApple OSS Distributions 	fMachineState     = kIOPM_DriverThreadCallDone;
5035*c54f35caSApple OSS Distributions 	fDriverCallReason = kDriverCallSetPowerState;
5036*c54f35caSApple OSS Distributions 
5037*c54f35caSApple OSS Distributions 	if (notifyControllingDriver() == false) {
5038*c54f35caSApple OSS Distributions 		notifyControllingDriverDone();
5039*c54f35caSApple OSS Distributions 	}
5040*c54f35caSApple OSS Distributions }
5041*c54f35caSApple OSS Distributions 
5042*c54f35caSApple OSS Distributions //*********************************************************************************
5043*c54f35caSApple OSS Distributions // [private] OurChangeWaitForPowerSettle
5044*c54f35caSApple OSS Distributions //
5045*c54f35caSApple OSS Distributions // Our controlling driver has completed the power state change we initiated.
5046*c54f35caSApple OSS Distributions // Wait for the driver specified settle time to expire.
5047*c54f35caSApple OSS Distributions //*********************************************************************************
5048*c54f35caSApple OSS Distributions 
5049*c54f35caSApple OSS Distributions void
OurChangeWaitForPowerSettle(void)5050*c54f35caSApple OSS Distributions IOService::OurChangeWaitForPowerSettle( void )
5051*c54f35caSApple OSS Distributions {
5052*c54f35caSApple OSS Distributions 	fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
5053*c54f35caSApple OSS Distributions 	startSettleTimer();
5054*c54f35caSApple OSS Distributions }
5055*c54f35caSApple OSS Distributions 
5056*c54f35caSApple OSS Distributions //*********************************************************************************
5057*c54f35caSApple OSS Distributions // [private] OurChangeNotifyInterestedDriversDidChange
5058*c54f35caSApple OSS Distributions //
5059*c54f35caSApple OSS Distributions // Power has settled on a power change we initiated. Here we notify
5060*c54f35caSApple OSS Distributions // all our interested drivers post-change.
5061*c54f35caSApple OSS Distributions //*********************************************************************************
5062*c54f35caSApple OSS Distributions 
5063*c54f35caSApple OSS Distributions void
OurChangeNotifyInterestedDriversDidChange(void)5064*c54f35caSApple OSS Distributions IOService::OurChangeNotifyInterestedDriversDidChange( void )
5065*c54f35caSApple OSS Distributions {
5066*c54f35caSApple OSS Distributions 	IOPMrootDomain * rootDomain;
5067*c54f35caSApple OSS Distributions 	if ((rootDomain = getPMRootDomain()) == this) {
5068*c54f35caSApple OSS Distributions 		rootDomain->tracePoint( IS_POWER_DROP ?
5069*c54f35caSApple OSS Distributions 		    kIOPMTracePointSleepDidChangeInterests :
5070*c54f35caSApple OSS Distributions 		    kIOPMTracePointWakeDidChangeInterests  );
5071*c54f35caSApple OSS Distributions 	}
5072*c54f35caSApple OSS Distributions 
5073*c54f35caSApple OSS Distributions 	notifyAll( kIOPM_OurChangeTellCapabilityDidChange );
5074*c54f35caSApple OSS Distributions }
5075*c54f35caSApple OSS Distributions 
5076*c54f35caSApple OSS Distributions //*********************************************************************************
5077*c54f35caSApple OSS Distributions // [private] OurChangeTellCapabilityDidChange
5078*c54f35caSApple OSS Distributions //
5079*c54f35caSApple OSS Distributions // For root domain to notify capability power-change.
5080*c54f35caSApple OSS Distributions //*********************************************************************************
5081*c54f35caSApple OSS Distributions 
5082*c54f35caSApple OSS Distributions void
OurChangeTellCapabilityDidChange(void)5083*c54f35caSApple OSS Distributions IOService::OurChangeTellCapabilityDidChange( void )
5084*c54f35caSApple OSS Distributions {
5085*c54f35caSApple OSS Distributions 	if (!IS_ROOT_DOMAIN) {
5086*c54f35caSApple OSS Distributions 		return OurChangeFinish();
5087*c54f35caSApple OSS Distributions 	}
5088*c54f35caSApple OSS Distributions 
5089*c54f35caSApple OSS Distributions 	if (!IS_POWER_DROP) {
5090*c54f35caSApple OSS Distributions 		// Notify root domain immediately after notifying interested
5091*c54f35caSApple OSS Distributions 		// drivers and power children.
5092*c54f35caSApple OSS Distributions 		getPMRootDomain()->willTellSystemCapabilityDidChange();
5093*c54f35caSApple OSS Distributions 	}
5094*c54f35caSApple OSS Distributions 
5095*c54f35caSApple OSS Distributions 	getPMRootDomain()->tracePoint( IS_POWER_DROP ?
5096*c54f35caSApple OSS Distributions 	    kIOPMTracePointSleepCapabilityClients :
5097*c54f35caSApple OSS Distributions 	    kIOPMTracePointWakeCapabilityClients  );
5098*c54f35caSApple OSS Distributions 
5099*c54f35caSApple OSS Distributions 	tellSystemCapabilityChange( kIOPM_OurChangeFinish );
5100*c54f35caSApple OSS Distributions }
5101*c54f35caSApple OSS Distributions 
5102*c54f35caSApple OSS Distributions //*********************************************************************************
5103*c54f35caSApple OSS Distributions // [private] OurChangeFinish
5104*c54f35caSApple OSS Distributions //
5105*c54f35caSApple OSS Distributions // Done with this self-induced power state change.
5106*c54f35caSApple OSS Distributions //*********************************************************************************
5107*c54f35caSApple OSS Distributions 
5108*c54f35caSApple OSS Distributions void
OurChangeFinish(void)5109*c54f35caSApple OSS Distributions IOService::OurChangeFinish( void )
5110*c54f35caSApple OSS Distributions {
5111*c54f35caSApple OSS Distributions 	all_done();
5112*c54f35caSApple OSS Distributions }
5113*c54f35caSApple OSS Distributions 
5114*c54f35caSApple OSS Distributions // MARK: -
5115*c54f35caSApple OSS Distributions // MARK: Power Change Initiated by Parent
5116*c54f35caSApple OSS Distributions 
5117*c54f35caSApple OSS Distributions //*********************************************************************************
5118*c54f35caSApple OSS Distributions // [private] ParentChangeStart
5119*c54f35caSApple OSS Distributions //
5120*c54f35caSApple OSS Distributions // Here we begin the processing of a power change initiated by our parent.
5121*c54f35caSApple OSS Distributions //*********************************************************************************
5122*c54f35caSApple OSS Distributions 
5123*c54f35caSApple OSS Distributions IOReturn
ParentChangeStart(void)5124*c54f35caSApple OSS Distributions IOService::ParentChangeStart( void )
5125*c54f35caSApple OSS Distributions {
5126*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
5127*c54f35caSApple OSS Distributions 	OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
5128*c54f35caSApple OSS Distributions 
5129*c54f35caSApple OSS Distributions 	// Root power domain has transitioned to its max power state
5130*c54f35caSApple OSS Distributions 	if ((fHeadNoteChangeFlags & (kIOPMDomainDidChange | kIOPMRootChangeUp)) ==
5131*c54f35caSApple OSS Distributions 	    (kIOPMDomainDidChange | kIOPMRootChangeUp)) {
5132*c54f35caSApple OSS Distributions 		// Restart the idle timer stopped by ParentChangeRootChangeDown()
5133*c54f35caSApple OSS Distributions 		if (fIdleTimerPeriod && fIdleTimerStopped) {
5134*c54f35caSApple OSS Distributions 			restartIdleTimer();
5135*c54f35caSApple OSS Distributions 		}
5136*c54f35caSApple OSS Distributions 	}
5137*c54f35caSApple OSS Distributions 
5138*c54f35caSApple OSS Distributions 	// Power domain is forcing us to lower power
5139*c54f35caSApple OSS Distributions 	if (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState)) {
5140*c54f35caSApple OSS Distributions 		PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
5141*c54f35caSApple OSS Distributions 
5142*c54f35caSApple OSS Distributions 		// Tell apps and kernel clients
5143*c54f35caSApple OSS Distributions 		fInitialPowerChange = false;
5144*c54f35caSApple OSS Distributions 		fMachineState = kIOPM_ParentChangeTellPriorityClientsPowerDown;
5145*c54f35caSApple OSS Distributions 		tellChangeDown1(fHeadNotePowerState);
5146*c54f35caSApple OSS Distributions 		return IOPMWillAckLater;
5147*c54f35caSApple OSS Distributions 	}
5148*c54f35caSApple OSS Distributions 
5149*c54f35caSApple OSS Distributions 	// Power domain is allowing us to raise power up to fHeadNotePowerState
5150*c54f35caSApple OSS Distributions 	if (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState)) {
5151*c54f35caSApple OSS Distributions 		if (StateOrder(fDesiredPowerState) > StateOrder(fCurrentPowerState)) {
5152*c54f35caSApple OSS Distributions 			if (StateOrder(fDesiredPowerState) < StateOrder(fHeadNotePowerState)) {
5153*c54f35caSApple OSS Distributions 				// We power up, but not all the way
5154*c54f35caSApple OSS Distributions 				fHeadNotePowerState = fDesiredPowerState;
5155*c54f35caSApple OSS Distributions 				fHeadNotePowerArrayEntry = &fPowerStates[fDesiredPowerState];
5156*c54f35caSApple OSS Distributions 				OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
5157*c54f35caSApple OSS Distributions 			}
5158*c54f35caSApple OSS Distributions 		} else {
5159*c54f35caSApple OSS Distributions 			// We don't need to change
5160*c54f35caSApple OSS Distributions 			fHeadNotePowerState = fCurrentPowerState;
5161*c54f35caSApple OSS Distributions 			fHeadNotePowerArrayEntry = &fPowerStates[fCurrentPowerState];
5162*c54f35caSApple OSS Distributions 			OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
5163*c54f35caSApple OSS Distributions 		}
5164*c54f35caSApple OSS Distributions 	}
5165*c54f35caSApple OSS Distributions 
5166*c54f35caSApple OSS Distributions 	if (fHeadNoteChangeFlags & kIOPMDomainDidChange) {
5167*c54f35caSApple OSS Distributions 		if (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState)) {
5168*c54f35caSApple OSS Distributions 			PM_ACTION_CHANGE(actionPowerChangeStart,
5169*c54f35caSApple OSS Distributions 			    fHeadNotePowerState, &fHeadNoteChangeFlags);
5170*c54f35caSApple OSS Distributions 
5171*c54f35caSApple OSS Distributions 			// Parent did change up - start our change up
5172*c54f35caSApple OSS Distributions 			fInitialPowerChange = false;
5173*c54f35caSApple OSS Distributions 			ParentChangeTellCapabilityWillChange();
5174*c54f35caSApple OSS Distributions 			return IOPMWillAckLater;
5175*c54f35caSApple OSS Distributions 		} else if (fHeadNoteChangeFlags & kIOPMRootBroadcastFlags) {
5176*c54f35caSApple OSS Distributions 			// No need to change power state, but broadcast change
5177*c54f35caSApple OSS Distributions 			// to our children.
5178*c54f35caSApple OSS Distributions 			fMachineState     = kIOPM_SyncNotifyDidChange;
5179*c54f35caSApple OSS Distributions 			fDriverCallReason = kDriverCallInformPreChange;
5180*c54f35caSApple OSS Distributions 			fHeadNoteChangeFlags |= kIOPMNotDone;
5181*c54f35caSApple OSS Distributions 			notifyChildren();
5182*c54f35caSApple OSS Distributions 			return IOPMWillAckLater;
5183*c54f35caSApple OSS Distributions 		}
5184*c54f35caSApple OSS Distributions 	}
5185*c54f35caSApple OSS Distributions 
5186*c54f35caSApple OSS Distributions 	// No power state change necessary
5187*c54f35caSApple OSS Distributions 	fHeadNoteChangeFlags |= kIOPMNotDone;
5188*c54f35caSApple OSS Distributions 
5189*c54f35caSApple OSS Distributions 	all_done();
5190*c54f35caSApple OSS Distributions 	return IOPMAckImplied;
5191*c54f35caSApple OSS Distributions }
5192*c54f35caSApple OSS Distributions 
5193*c54f35caSApple OSS Distributions //******************************************************************************
5194*c54f35caSApple OSS Distributions // [private] ParentChangeRootChangeDown
5195*c54f35caSApple OSS Distributions //
5196*c54f35caSApple OSS Distributions // Root domain has finished the transition to the system sleep state. And all
5197*c54f35caSApple OSS Distributions // drivers in the power plane should have powered down. Cancel the idle timer,
5198*c54f35caSApple OSS Distributions // and also reset the device desire for those drivers that don't want power
5199*c54f35caSApple OSS Distributions // automatically restored on wake.
5200*c54f35caSApple OSS Distributions //******************************************************************************
5201*c54f35caSApple OSS Distributions 
5202*c54f35caSApple OSS Distributions void
ParentChangeRootChangeDown(void)5203*c54f35caSApple OSS Distributions IOService::ParentChangeRootChangeDown( void )
5204*c54f35caSApple OSS Distributions {
5205*c54f35caSApple OSS Distributions 	// Always stop the idle timer before root power down
5206*c54f35caSApple OSS Distributions 	if (fIdleTimerPeriod && !fIdleTimerStopped) {
5207*c54f35caSApple OSS Distributions 		fIdleTimerStopped = true;
5208*c54f35caSApple OSS Distributions 		if (fIdleTimer && thread_call_cancel(fIdleTimer)) {
5209*c54f35caSApple OSS Distributions 			release();
5210*c54f35caSApple OSS Distributions 		}
5211*c54f35caSApple OSS Distributions 	}
5212*c54f35caSApple OSS Distributions 
5213*c54f35caSApple OSS Distributions 	if (fResetPowerStateOnWake) {
5214*c54f35caSApple OSS Distributions 		// Reset device desire down to the lowest power state.
5215*c54f35caSApple OSS Distributions 		// Advisory tickle desire is intentionally untouched since
5216*c54f35caSApple OSS Distributions 		// it has no effect until system is promoted to full wake.
5217*c54f35caSApple OSS Distributions 
5218*c54f35caSApple OSS Distributions 		if (fDeviceDesire != kPowerStateZero) {
5219*c54f35caSApple OSS Distributions 			updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
5220*c54f35caSApple OSS Distributions 			computeDesiredState(kPowerStateZero, true);
5221*c54f35caSApple OSS Distributions 			requestDomainPower( fDesiredPowerState );
5222*c54f35caSApple OSS Distributions 			PM_LOG1("%s: tickle desire removed\n", fName);
5223*c54f35caSApple OSS Distributions 		}
5224*c54f35caSApple OSS Distributions 
5225*c54f35caSApple OSS Distributions 		// Invalidate tickle cache so the next tickle will issue a request
5226*c54f35caSApple OSS Distributions 		IOLockLock(fActivityLock);
5227*c54f35caSApple OSS Distributions 		fDeviceWasActive = false;
5228*c54f35caSApple OSS Distributions 		fActivityTicklePowerState = kInvalidTicklePowerState;
5229*c54f35caSApple OSS Distributions 		IOLockUnlock(fActivityLock);
5230*c54f35caSApple OSS Distributions 
5231*c54f35caSApple OSS Distributions 		fIdleTimerMinPowerState = kPowerStateZero;
5232*c54f35caSApple OSS Distributions 	} else if (fAdvisoryTickleUsed) {
5233*c54f35caSApple OSS Distributions 		// Less aggressive mechanism to accelerate idle timer expiration
5234*c54f35caSApple OSS Distributions 		// before system sleep. May not always allow the driver to wake
5235*c54f35caSApple OSS Distributions 		// up from system sleep in the min power state.
5236*c54f35caSApple OSS Distributions 
5237*c54f35caSApple OSS Distributions 		AbsoluteTime    now;
5238*c54f35caSApple OSS Distributions 		uint64_t        nsec;
5239*c54f35caSApple OSS Distributions 		bool            dropTickleDesire = false;
5240*c54f35caSApple OSS Distributions 
5241*c54f35caSApple OSS Distributions 		if (fIdleTimerPeriod && !fIdleTimerIgnored &&
5242*c54f35caSApple OSS Distributions 		    (fIdleTimerMinPowerState == kPowerStateZero) &&
5243*c54f35caSApple OSS Distributions 		    (fDeviceDesire != kPowerStateZero)) {
5244*c54f35caSApple OSS Distributions 			IOLockLock(fActivityLock);
5245*c54f35caSApple OSS Distributions 
5246*c54f35caSApple OSS Distributions 			if (!fDeviceWasActive) {
5247*c54f35caSApple OSS Distributions 				// No tickles since the last idle timer expiration.
5248*c54f35caSApple OSS Distributions 				// Safe to drop the device desire to zero.
5249*c54f35caSApple OSS Distributions 				dropTickleDesire = true;
5250*c54f35caSApple OSS Distributions 			} else {
5251*c54f35caSApple OSS Distributions 				// Was tickled since the last idle timer expiration,
5252*c54f35caSApple OSS Distributions 				// but not in the last minute.
5253*c54f35caSApple OSS Distributions 				clock_get_uptime(&now);
5254*c54f35caSApple OSS Distributions 				SUB_ABSOLUTETIME(&now, &fDeviceActiveTimestamp);
5255*c54f35caSApple OSS Distributions 				absolutetime_to_nanoseconds(now, &nsec);
5256*c54f35caSApple OSS Distributions 				if (nsec >= kNoTickleCancelWindow) {
5257*c54f35caSApple OSS Distributions 					dropTickleDesire = true;
5258*c54f35caSApple OSS Distributions 				}
5259*c54f35caSApple OSS Distributions 			}
5260*c54f35caSApple OSS Distributions 
5261*c54f35caSApple OSS Distributions 			if (dropTickleDesire) {
5262*c54f35caSApple OSS Distributions 				// Force the next tickle to raise power state
5263*c54f35caSApple OSS Distributions 				fDeviceWasActive = false;
5264*c54f35caSApple OSS Distributions 				fActivityTicklePowerState = kInvalidTicklePowerState;
5265*c54f35caSApple OSS Distributions 			}
5266*c54f35caSApple OSS Distributions 
5267*c54f35caSApple OSS Distributions 			IOLockUnlock(fActivityLock);
5268*c54f35caSApple OSS Distributions 		}
5269*c54f35caSApple OSS Distributions 
5270*c54f35caSApple OSS Distributions 		if (dropTickleDesire) {
5271*c54f35caSApple OSS Distributions 			// Advisory tickle desire is intentionally untouched since
5272*c54f35caSApple OSS Distributions 			// it has no effect until system is promoted to full wake.
5273*c54f35caSApple OSS Distributions 
5274*c54f35caSApple OSS Distributions 			updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
5275*c54f35caSApple OSS Distributions 			computeDesiredState(kPowerStateZero, true);
5276*c54f35caSApple OSS Distributions 			PM_LOG1("%s: tickle desire dropped\n", fName);
5277*c54f35caSApple OSS Distributions 		}
5278*c54f35caSApple OSS Distributions 	}
5279*c54f35caSApple OSS Distributions }
5280*c54f35caSApple OSS Distributions 
5281*c54f35caSApple OSS Distributions //*********************************************************************************
5282*c54f35caSApple OSS Distributions // [private] ParentChangeTellPriorityClientsPowerDown
5283*c54f35caSApple OSS Distributions //
5284*c54f35caSApple OSS Distributions // All applications and kernel clients have acknowledged our intention to drop
5285*c54f35caSApple OSS Distributions // power.  Here we notify "priority" clients that we are lowering power.
5286*c54f35caSApple OSS Distributions //*********************************************************************************
5287*c54f35caSApple OSS Distributions 
5288*c54f35caSApple OSS Distributions void
ParentChangeTellPriorityClientsPowerDown(void)5289*c54f35caSApple OSS Distributions IOService::ParentChangeTellPriorityClientsPowerDown( void )
5290*c54f35caSApple OSS Distributions {
5291*c54f35caSApple OSS Distributions 	fMachineState = kIOPM_ParentChangeNotifyInterestedDriversWillChange;
5292*c54f35caSApple OSS Distributions 	tellChangeDown2(fHeadNotePowerState);
5293*c54f35caSApple OSS Distributions }
5294*c54f35caSApple OSS Distributions 
5295*c54f35caSApple OSS Distributions //*********************************************************************************
5296*c54f35caSApple OSS Distributions // [private] ParentChangeTellCapabilityWillChange
5297*c54f35caSApple OSS Distributions //
5298*c54f35caSApple OSS Distributions // All (legacy) applications and kernel clients have acknowledged, extra stage for
5299*c54f35caSApple OSS Distributions // root domain to notify apps and drivers about the system capability change.
5300*c54f35caSApple OSS Distributions //*********************************************************************************
5301*c54f35caSApple OSS Distributions 
5302*c54f35caSApple OSS Distributions void
ParentChangeTellCapabilityWillChange(void)5303*c54f35caSApple OSS Distributions IOService::ParentChangeTellCapabilityWillChange( void )
5304*c54f35caSApple OSS Distributions {
5305*c54f35caSApple OSS Distributions 	if (!IS_ROOT_DOMAIN) {
5306*c54f35caSApple OSS Distributions 		return ParentChangeNotifyInterestedDriversWillChange();
5307*c54f35caSApple OSS Distributions 	}
5308*c54f35caSApple OSS Distributions 
5309*c54f35caSApple OSS Distributions 	tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange );
5310*c54f35caSApple OSS Distributions }
5311*c54f35caSApple OSS Distributions 
5312*c54f35caSApple OSS Distributions //*********************************************************************************
5313*c54f35caSApple OSS Distributions // [private] ParentChangeNotifyInterestedDriversWillChange
5314*c54f35caSApple OSS Distributions //
5315*c54f35caSApple OSS Distributions // All applications and kernel clients have acknowledged our power state change.
5316*c54f35caSApple OSS Distributions // Here we notify interested drivers pre-change.
5317*c54f35caSApple OSS Distributions //*********************************************************************************
5318*c54f35caSApple OSS Distributions 
5319*c54f35caSApple OSS Distributions void
ParentChangeNotifyInterestedDriversWillChange(void)5320*c54f35caSApple OSS Distributions IOService::ParentChangeNotifyInterestedDriversWillChange( void )
5321*c54f35caSApple OSS Distributions {
5322*c54f35caSApple OSS Distributions 	notifyAll( kIOPM_ParentChangeSetPowerState );
5323*c54f35caSApple OSS Distributions }
5324*c54f35caSApple OSS Distributions 
5325*c54f35caSApple OSS Distributions //*********************************************************************************
5326*c54f35caSApple OSS Distributions // [private] ParentChangeSetPowerState
5327*c54f35caSApple OSS Distributions //
5328*c54f35caSApple OSS Distributions // Instruct our controlling driver to program the hardware for the power state
5329*c54f35caSApple OSS Distributions // change. Wait for async completions.
5330*c54f35caSApple OSS Distributions //*********************************************************************************
5331*c54f35caSApple OSS Distributions 
5332*c54f35caSApple OSS Distributions void
ParentChangeSetPowerState(void)5333*c54f35caSApple OSS Distributions IOService::ParentChangeSetPowerState( void )
5334*c54f35caSApple OSS Distributions {
5335*c54f35caSApple OSS Distributions 	MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle );
5336*c54f35caSApple OSS Distributions 	fMachineState     = kIOPM_DriverThreadCallDone;
5337*c54f35caSApple OSS Distributions 	fDriverCallReason = kDriverCallSetPowerState;
5338*c54f35caSApple OSS Distributions 
5339*c54f35caSApple OSS Distributions 	if (notifyControllingDriver() == false) {
5340*c54f35caSApple OSS Distributions 		notifyControllingDriverDone();
5341*c54f35caSApple OSS Distributions 	}
5342*c54f35caSApple OSS Distributions }
5343*c54f35caSApple OSS Distributions 
5344*c54f35caSApple OSS Distributions //*********************************************************************************
5345*c54f35caSApple OSS Distributions // [private] ParentChangeWaitForPowerSettle
5346*c54f35caSApple OSS Distributions //
5347*c54f35caSApple OSS Distributions // Our controlling driver has completed the power state change initiated by our
5348*c54f35caSApple OSS Distributions // parent. Wait for the driver specified settle time to expire.
5349*c54f35caSApple OSS Distributions //*********************************************************************************
5350*c54f35caSApple OSS Distributions 
5351*c54f35caSApple OSS Distributions void
ParentChangeWaitForPowerSettle(void)5352*c54f35caSApple OSS Distributions IOService::ParentChangeWaitForPowerSettle( void )
5353*c54f35caSApple OSS Distributions {
5354*c54f35caSApple OSS Distributions 	fMachineState = kIOPM_ParentChangeNotifyInterestedDriversDidChange;
5355*c54f35caSApple OSS Distributions 	startSettleTimer();
5356*c54f35caSApple OSS Distributions }
5357*c54f35caSApple OSS Distributions 
5358*c54f35caSApple OSS Distributions //*********************************************************************************
5359*c54f35caSApple OSS Distributions // [private] ParentChangeNotifyInterestedDriversDidChange
5360*c54f35caSApple OSS Distributions //
5361*c54f35caSApple OSS Distributions // Power has settled on a power change initiated by our parent. Here we notify
5362*c54f35caSApple OSS Distributions // all our interested drivers post-change.
5363*c54f35caSApple OSS Distributions //*********************************************************************************
5364*c54f35caSApple OSS Distributions 
5365*c54f35caSApple OSS Distributions void
ParentChangeNotifyInterestedDriversDidChange(void)5366*c54f35caSApple OSS Distributions IOService::ParentChangeNotifyInterestedDriversDidChange( void )
5367*c54f35caSApple OSS Distributions {
5368*c54f35caSApple OSS Distributions 	notifyAll( kIOPM_ParentChangeTellCapabilityDidChange );
5369*c54f35caSApple OSS Distributions }
5370*c54f35caSApple OSS Distributions 
5371*c54f35caSApple OSS Distributions //*********************************************************************************
5372*c54f35caSApple OSS Distributions // [private] ParentChangeTellCapabilityDidChange
5373*c54f35caSApple OSS Distributions //
5374*c54f35caSApple OSS Distributions // For root domain to notify capability power-change.
5375*c54f35caSApple OSS Distributions //*********************************************************************************
5376*c54f35caSApple OSS Distributions 
5377*c54f35caSApple OSS Distributions void
ParentChangeTellCapabilityDidChange(void)5378*c54f35caSApple OSS Distributions IOService::ParentChangeTellCapabilityDidChange( void )
5379*c54f35caSApple OSS Distributions {
5380*c54f35caSApple OSS Distributions 	if (!IS_ROOT_DOMAIN) {
5381*c54f35caSApple OSS Distributions 		return ParentChangeAcknowledgePowerChange();
5382*c54f35caSApple OSS Distributions 	}
5383*c54f35caSApple OSS Distributions 
5384*c54f35caSApple OSS Distributions 	tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange );
5385*c54f35caSApple OSS Distributions }
5386*c54f35caSApple OSS Distributions 
5387*c54f35caSApple OSS Distributions //*********************************************************************************
5388*c54f35caSApple OSS Distributions // [private] ParentAcknowledgePowerChange
5389*c54f35caSApple OSS Distributions //
5390*c54f35caSApple OSS Distributions // Acknowledge our power parent that our power change is done.
5391*c54f35caSApple OSS Distributions //*********************************************************************************
5392*c54f35caSApple OSS Distributions 
5393*c54f35caSApple OSS Distributions void
ParentChangeAcknowledgePowerChange(void)5394*c54f35caSApple OSS Distributions IOService::ParentChangeAcknowledgePowerChange( void )
5395*c54f35caSApple OSS Distributions {
5396*c54f35caSApple OSS Distributions 	IORegistryEntry *   nub;
5397*c54f35caSApple OSS Distributions 	IOService *         parent;
5398*c54f35caSApple OSS Distributions 
5399*c54f35caSApple OSS Distributions 	nub = fHeadNoteParentConnection;
5400*c54f35caSApple OSS Distributions 	nub->retain();
5401*c54f35caSApple OSS Distributions 	all_done();
5402*c54f35caSApple OSS Distributions 	parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
5403*c54f35caSApple OSS Distributions 	if (parent) {
5404*c54f35caSApple OSS Distributions 		parent->acknowledgePowerChange((IOService *)nub);
5405*c54f35caSApple OSS Distributions 		parent->release();
5406*c54f35caSApple OSS Distributions 	}
5407*c54f35caSApple OSS Distributions 	nub->release();
5408*c54f35caSApple OSS Distributions }
5409*c54f35caSApple OSS Distributions 
5410*c54f35caSApple OSS Distributions // MARK: -
5411*c54f35caSApple OSS Distributions // MARK: Ack and Settle timers
5412*c54f35caSApple OSS Distributions 
5413*c54f35caSApple OSS Distributions //*********************************************************************************
5414*c54f35caSApple OSS Distributions // [private] settleTimerExpired
5415*c54f35caSApple OSS Distributions //
5416*c54f35caSApple OSS Distributions // Power has settled after our last change.  Notify interested parties that
5417*c54f35caSApple OSS Distributions // there is a new power state.
5418*c54f35caSApple OSS Distributions //*********************************************************************************
5419*c54f35caSApple OSS Distributions 
5420*c54f35caSApple OSS Distributions void
settleTimerExpired(void)5421*c54f35caSApple OSS Distributions IOService::settleTimerExpired( void )
5422*c54f35caSApple OSS Distributions {
5423*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
5424*c54f35caSApple OSS Distributions 	fSettleTimeUS = 0;
5425*c54f35caSApple OSS Distributions 	gIOPMWorkQueue->signalWorkAvailable();
5426*c54f35caSApple OSS Distributions #endif
5427*c54f35caSApple OSS Distributions }
5428*c54f35caSApple OSS Distributions 
5429*c54f35caSApple OSS Distributions //*********************************************************************************
5430*c54f35caSApple OSS Distributions // settle_timer_expired
5431*c54f35caSApple OSS Distributions //
5432*c54f35caSApple OSS Distributions // Holds a retain while the settle timer callout is in flight.
5433*c54f35caSApple OSS Distributions //*********************************************************************************
5434*c54f35caSApple OSS Distributions 
5435*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
5436*c54f35caSApple OSS Distributions static void
settle_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5437*c54f35caSApple OSS Distributions settle_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5438*c54f35caSApple OSS Distributions {
5439*c54f35caSApple OSS Distributions 	IOService * me = (IOService *) arg0;
5440*c54f35caSApple OSS Distributions 
5441*c54f35caSApple OSS Distributions 	if (gIOPMWorkLoop && gIOPMWorkQueue) {
5442*c54f35caSApple OSS Distributions 		gIOPMWorkLoop->runAction(
5443*c54f35caSApple OSS Distributions 			OSMemberFunctionCast(IOWorkLoop::Action, me, &IOService::settleTimerExpired),
5444*c54f35caSApple OSS Distributions 			me);
5445*c54f35caSApple OSS Distributions 	}
5446*c54f35caSApple OSS Distributions 	me->release();
5447*c54f35caSApple OSS Distributions }
5448*c54f35caSApple OSS Distributions #endif
5449*c54f35caSApple OSS Distributions 
5450*c54f35caSApple OSS Distributions //*********************************************************************************
5451*c54f35caSApple OSS Distributions // [private] startSettleTimer
5452*c54f35caSApple OSS Distributions //
5453*c54f35caSApple OSS Distributions // Calculate a power-settling delay in microseconds and start a timer.
5454*c54f35caSApple OSS Distributions //*********************************************************************************
5455*c54f35caSApple OSS Distributions 
5456*c54f35caSApple OSS Distributions void
startSettleTimer(void)5457*c54f35caSApple OSS Distributions IOService::startSettleTimer( void )
5458*c54f35caSApple OSS Distributions {
5459*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
5460*c54f35caSApple OSS Distributions 	// This function is broken and serves no useful purpose since it never
5461*c54f35caSApple OSS Distributions 	// updates fSettleTimeUS to a non-zero value to stall the state machine,
5462*c54f35caSApple OSS Distributions 	// yet it starts a delay timer. It appears no driver relies on a delay
5463*c54f35caSApple OSS Distributions 	// from settleUpTime and settleDownTime in the power state table.
5464*c54f35caSApple OSS Distributions 
5465*c54f35caSApple OSS Distributions 	AbsoluteTime        deadline;
5466*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex stateIndex;
5467*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex currentOrder, newOrder, i;
5468*c54f35caSApple OSS Distributions 	uint32_t            settleTime = 0;
5469*c54f35caSApple OSS Distributions 	boolean_t           pending;
5470*c54f35caSApple OSS Distributions 
5471*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
5472*c54f35caSApple OSS Distributions 
5473*c54f35caSApple OSS Distributions 	currentOrder = StateOrder(fCurrentPowerState);
5474*c54f35caSApple OSS Distributions 	newOrder     = StateOrder(fHeadNotePowerState);
5475*c54f35caSApple OSS Distributions 
5476*c54f35caSApple OSS Distributions 	i = currentOrder;
5477*c54f35caSApple OSS Distributions 
5478*c54f35caSApple OSS Distributions 	// lowering power
5479*c54f35caSApple OSS Distributions 	if (newOrder < currentOrder) {
5480*c54f35caSApple OSS Distributions 		while (i > newOrder) {
5481*c54f35caSApple OSS Distributions 			stateIndex = fPowerStates[i].stateOrderToIndex;
5482*c54f35caSApple OSS Distributions 			settleTime += (uint32_t) fPowerStates[stateIndex].settleDownTime;
5483*c54f35caSApple OSS Distributions 			i--;
5484*c54f35caSApple OSS Distributions 		}
5485*c54f35caSApple OSS Distributions 	}
5486*c54f35caSApple OSS Distributions 
5487*c54f35caSApple OSS Distributions 	// raising power
5488*c54f35caSApple OSS Distributions 	if (newOrder > currentOrder) {
5489*c54f35caSApple OSS Distributions 		while (i < newOrder) {
5490*c54f35caSApple OSS Distributions 			stateIndex = fPowerStates[i + 1].stateOrderToIndex;
5491*c54f35caSApple OSS Distributions 			settleTime += (uint32_t) fPowerStates[stateIndex].settleUpTime;
5492*c54f35caSApple OSS Distributions 			i++;
5493*c54f35caSApple OSS Distributions 		}
5494*c54f35caSApple OSS Distributions 	}
5495*c54f35caSApple OSS Distributions 
5496*c54f35caSApple OSS Distributions 	if (settleTime) {
5497*c54f35caSApple OSS Distributions 		retain();
5498*c54f35caSApple OSS Distributions 		clock_interval_to_deadline(settleTime, kMicrosecondScale, &deadline);
5499*c54f35caSApple OSS Distributions 		pending = thread_call_enter_delayed(fSettleTimer, deadline);
5500*c54f35caSApple OSS Distributions 		if (pending) {
5501*c54f35caSApple OSS Distributions 			release();
5502*c54f35caSApple OSS Distributions 		}
5503*c54f35caSApple OSS Distributions 	}
5504*c54f35caSApple OSS Distributions #endif
5505*c54f35caSApple OSS Distributions }
5506*c54f35caSApple OSS Distributions 
5507*c54f35caSApple OSS Distributions //*********************************************************************************
5508*c54f35caSApple OSS Distributions // [private] ackTimerTick
5509*c54f35caSApple OSS Distributions //
5510*c54f35caSApple OSS Distributions // The acknowledgement timeout periodic timer has ticked.
5511*c54f35caSApple OSS Distributions // If we are awaiting acks for a power change notification,
5512*c54f35caSApple OSS Distributions // we decrement the timer word of each interested driver which hasn't acked.
5513*c54f35caSApple OSS Distributions // If a timer word becomes zero, we pretend the driver aknowledged.
5514*c54f35caSApple OSS Distributions // If we are waiting for the controlling driver to change the power
5515*c54f35caSApple OSS Distributions // state of the hardware, we decrement its timer word, and if it becomes
5516*c54f35caSApple OSS Distributions // zero, we pretend the driver acknowledged.
5517*c54f35caSApple OSS Distributions //
5518*c54f35caSApple OSS Distributions // Returns true if the timer tick made it possible to advance to the next
5519*c54f35caSApple OSS Distributions // machine state, false otherwise.
5520*c54f35caSApple OSS Distributions //*********************************************************************************
5521*c54f35caSApple OSS Distributions 
5522*c54f35caSApple OSS Distributions #ifndef __LP64__
5523*c54f35caSApple OSS Distributions #if MACH_ASSERT
5524*c54f35caSApple OSS Distributions __dead2
5525*c54f35caSApple OSS Distributions #endif
5526*c54f35caSApple OSS Distributions void
ack_timer_ticked(void)5527*c54f35caSApple OSS Distributions IOService::ack_timer_ticked( void )
5528*c54f35caSApple OSS Distributions {
5529*c54f35caSApple OSS Distributions 	assert(false);
5530*c54f35caSApple OSS Distributions }
5531*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
5532*c54f35caSApple OSS Distributions 
5533*c54f35caSApple OSS Distributions bool
ackTimerTick(void)5534*c54f35caSApple OSS Distributions IOService::ackTimerTick( void )
5535*c54f35caSApple OSS Distributions {
5536*c54f35caSApple OSS Distributions 	IOPMinformee *      nextObject;
5537*c54f35caSApple OSS Distributions 	bool                done = false;
5538*c54f35caSApple OSS Distributions 
5539*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
5540*c54f35caSApple OSS Distributions 	switch (fMachineState) {
5541*c54f35caSApple OSS Distributions 	case kIOPM_OurChangeWaitForPowerSettle:
5542*c54f35caSApple OSS Distributions 	case kIOPM_ParentChangeWaitForPowerSettle:
5543*c54f35caSApple OSS Distributions 		// are we waiting for controlling driver to acknowledge?
5544*c54f35caSApple OSS Distributions 		if (fDriverTimer > 0) {
5545*c54f35caSApple OSS Distributions 			// yes, decrement timer tick
5546*c54f35caSApple OSS Distributions 			fDriverTimer--;
5547*c54f35caSApple OSS Distributions 			if (fDriverTimer == 0) {
5548*c54f35caSApple OSS Distributions 				// controlling driver is tardy
5549*c54f35caSApple OSS Distributions 				uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
5550*c54f35caSApple OSS Distributions 				OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
5551*c54f35caSApple OSS Distributions 				setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
5552*c54f35caSApple OSS Distributions 				PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
5553*c54f35caSApple OSS Distributions 				    fName, OBFUSCATE(this), fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5554*c54f35caSApple OSS Distributions 
5555*c54f35caSApple OSS Distributions #if DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)
5556*c54f35caSApple OSS Distributions 				bool panic_allowed = false;
5557*c54f35caSApple OSS Distributions 				uint32_t setpowerstate_panic = -1;
5558*c54f35caSApple OSS Distributions 				PE_parse_boot_argn("setpowerstate_panic", &setpowerstate_panic, sizeof(setpowerstate_panic));
5559*c54f35caSApple OSS Distributions 				panic_allowed = setpowerstate_panic != 0;
5560*c54f35caSApple OSS Distributions #ifdef CONFIG_XNUPOST
5561*c54f35caSApple OSS Distributions 				uint64_t kernel_post_args = 0;
5562*c54f35caSApple OSS Distributions 				PE_parse_boot_argn("kernPOST", &kernel_post_args, sizeof(kernel_post_args));
5563*c54f35caSApple OSS Distributions 				if (kernel_post_args != 0) {
5564*c54f35caSApple OSS Distributions 					panic_allowed = false;
5565*c54f35caSApple OSS Distributions 				}
5566*c54f35caSApple OSS Distributions #endif /* CONFIG_XNUPOST */
5567*c54f35caSApple OSS Distributions 				if (panic_allowed) {
5568*c54f35caSApple OSS Distributions 					// rdar://problem/48743340 - excluding AppleSEPManager from panic
5569*c54f35caSApple OSS Distributions 					const char *allowlist = "AppleSEPManager";
5570*c54f35caSApple OSS Distributions 					if (strncmp(fName, allowlist, strlen(allowlist))) {
5571*c54f35caSApple OSS Distributions 						panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
5572*c54f35caSApple OSS Distributions 						    fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5573*c54f35caSApple OSS Distributions 					}
5574*c54f35caSApple OSS Distributions 				} else {
5575*c54f35caSApple OSS Distributions #ifdef CONFIG_XNUPOST
5576*c54f35caSApple OSS Distributions 					if (kernel_post_args != 0) {
5577*c54f35caSApple OSS Distributions 						PM_ERROR("setPowerState panic disabled by kernPOST boot-arg\n");
5578*c54f35caSApple OSS Distributions 					}
5579*c54f35caSApple OSS Distributions #endif /* CONFIG_XNUPOST */
5580*c54f35caSApple OSS Distributions 					if (setpowerstate_panic != 0) {
5581*c54f35caSApple OSS Distributions 						PM_ERROR("setPowerState panic disabled by setpowerstate_panic boot-arg\n");
5582*c54f35caSApple OSS Distributions 					}
5583*c54f35caSApple OSS Distributions 				}
5584*c54f35caSApple OSS Distributions #else /* !(DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)) */
5585*c54f35caSApple OSS Distributions 				if (gIOKitDebug & kIOLogDebugPower) {
5586*c54f35caSApple OSS Distributions 					panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
5587*c54f35caSApple OSS Distributions 					    fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5588*c54f35caSApple OSS Distributions 				} else {
5589*c54f35caSApple OSS Distributions 					// panic for first party kexts
5590*c54f35caSApple OSS Distributions 					const void *function_addr = NULL;
5591*c54f35caSApple OSS Distributions 					OSKext *kext = NULL;
5592*c54f35caSApple OSS Distributions 					function_addr = OSMemberFunctionCast(const void *, fControllingDriver, &IOService::setPowerState);
5593*c54f35caSApple OSS Distributions 					kext = OSKext::lookupKextWithAddress((vm_address_t)function_addr);
5594*c54f35caSApple OSS Distributions 					if (kext) {
5595*c54f35caSApple OSS Distributions #if __has_feature(ptrauth_calls)
5596*c54f35caSApple OSS Distributions 						function_addr = (const void*)VM_KERNEL_STRIP_PTR(function_addr);
5597*c54f35caSApple OSS Distributions #endif /* __has_feature(ptrauth_calls) */
5598*c54f35caSApple OSS Distributions 						const char *bundleID = kext->getIdentifierCString();
5599*c54f35caSApple OSS Distributions 						const char *apple_prefix = "com.apple";
5600*c54f35caSApple OSS Distributions 						const char *kernel_prefix = "__kernel__";
5601*c54f35caSApple OSS Distributions 						if (strncmp(bundleID, apple_prefix, strlen(apple_prefix)) == 0 || strncmp(bundleID, kernel_prefix, strlen(kernel_prefix)) == 0) {
5602*c54f35caSApple OSS Distributions 							// first party client
5603*c54f35caSApple OSS Distributions 							panic("%s::setPowerState(%p : %p, %lu -> %lu) timed out after %d ms",
5604*c54f35caSApple OSS Distributions 							    fName, this, function_addr, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5605*c54f35caSApple OSS Distributions 						}
5606*c54f35caSApple OSS Distributions 						kext->release();
5607*c54f35caSApple OSS Distributions 					}
5608*c54f35caSApple OSS Distributions 				}
5609*c54f35caSApple OSS Distributions #endif /* !(DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)) */
5610*c54f35caSApple OSS Distributions 				// Unblock state machine and pretend driver has acked.
5611*c54f35caSApple OSS Distributions 				done = true;
5612*c54f35caSApple OSS Distributions 				getPMRootDomain()->reset_watchdog_timer(this, 0);
5613*c54f35caSApple OSS Distributions 			} else {
5614*c54f35caSApple OSS Distributions 				// still waiting, set timer again
5615*c54f35caSApple OSS Distributions 				start_ack_timer();
5616*c54f35caSApple OSS Distributions 			}
5617*c54f35caSApple OSS Distributions 		}
5618*c54f35caSApple OSS Distributions 		break;
5619*c54f35caSApple OSS Distributions 
5620*c54f35caSApple OSS Distributions 	case kIOPM_NotifyChildrenStart:
5621*c54f35caSApple OSS Distributions 		// are we waiting for interested parties to acknowledge?
5622*c54f35caSApple OSS Distributions 		if (fHeadNotePendingAcks != 0) {
5623*c54f35caSApple OSS Distributions 			// yes, go through the list of interested drivers
5624*c54f35caSApple OSS Distributions 			nextObject = fInterestedDrivers->firstInList();
5625*c54f35caSApple OSS Distributions 			// and check each one
5626*c54f35caSApple OSS Distributions 			while (nextObject != NULL) {
5627*c54f35caSApple OSS Distributions 				if (nextObject->timer > 0) {
5628*c54f35caSApple OSS Distributions 					nextObject->timer--;
5629*c54f35caSApple OSS Distributions 					// this one should have acked by now
5630*c54f35caSApple OSS Distributions 					if (nextObject->timer == 0) {
5631*c54f35caSApple OSS Distributions 						uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
5632*c54f35caSApple OSS Distributions 						OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
5633*c54f35caSApple OSS Distributions 						nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
5634*c54f35caSApple OSS Distributions 						PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
5635*c54f35caSApple OSS Distributions 						    nextObject->whatObject->getName(),
5636*c54f35caSApple OSS Distributions 						    (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
5637*c54f35caSApple OSS Distributions 						    OBFUSCATE(nextObject->whatObject), fName, fCurrentPowerState, fHeadNotePowerState,
5638*c54f35caSApple OSS Distributions 						    NS_TO_MS(nsec));
5639*c54f35caSApple OSS Distributions 
5640*c54f35caSApple OSS Distributions 						// Pretend driver has acked.
5641*c54f35caSApple OSS Distributions 						fHeadNotePendingAcks--;
5642*c54f35caSApple OSS Distributions 					}
5643*c54f35caSApple OSS Distributions 				}
5644*c54f35caSApple OSS Distributions 				nextObject = fInterestedDrivers->nextInList(nextObject);
5645*c54f35caSApple OSS Distributions 			}
5646*c54f35caSApple OSS Distributions 
5647*c54f35caSApple OSS Distributions 			// is that the last?
5648*c54f35caSApple OSS Distributions 			if (fHeadNotePendingAcks == 0) {
5649*c54f35caSApple OSS Distributions 				// yes, we can continue
5650*c54f35caSApple OSS Distributions 				done = true;
5651*c54f35caSApple OSS Distributions 				getPMRootDomain()->reset_watchdog_timer(this, 0);
5652*c54f35caSApple OSS Distributions 			} else {
5653*c54f35caSApple OSS Distributions 				// no, set timer again
5654*c54f35caSApple OSS Distributions 				start_ack_timer();
5655*c54f35caSApple OSS Distributions 			}
5656*c54f35caSApple OSS Distributions 		}
5657*c54f35caSApple OSS Distributions 		break;
5658*c54f35caSApple OSS Distributions 
5659*c54f35caSApple OSS Distributions 	// TODO: aggreggate this
5660*c54f35caSApple OSS Distributions 	case kIOPM_OurChangeTellClientsPowerDown:
5661*c54f35caSApple OSS Distributions 	case kIOPM_OurChangeTellUserPMPolicyPowerDown:
5662*c54f35caSApple OSS Distributions 	case kIOPM_OurChangeTellPriorityClientsPowerDown:
5663*c54f35caSApple OSS Distributions 	case kIOPM_OurChangeNotifyInterestedDriversWillChange:
5664*c54f35caSApple OSS Distributions 	case kIOPM_ParentChangeTellPriorityClientsPowerDown:
5665*c54f35caSApple OSS Distributions 	case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
5666*c54f35caSApple OSS Distributions 	case kIOPM_SyncTellClientsPowerDown:
5667*c54f35caSApple OSS Distributions 	case kIOPM_SyncTellPriorityClientsPowerDown:
5668*c54f35caSApple OSS Distributions 	case kIOPM_SyncNotifyWillChange:
5669*c54f35caSApple OSS Distributions 	case kIOPM_TellCapabilityChangeDone:
5670*c54f35caSApple OSS Distributions 		// apps didn't respond in time
5671*c54f35caSApple OSS Distributions 		cleanClientResponses(true);
5672*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogClientTardy, 0, 1);
5673*c54f35caSApple OSS Distributions 		// tardy equates to approval
5674*c54f35caSApple OSS Distributions 		done = true;
5675*c54f35caSApple OSS Distributions 		break;
5676*c54f35caSApple OSS Distributions 
5677*c54f35caSApple OSS Distributions 	default:
5678*c54f35caSApple OSS Distributions 		PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
5679*c54f35caSApple OSS Distributions 		    getName(), fMachineState);
5680*c54f35caSApple OSS Distributions 		break;
5681*c54f35caSApple OSS Distributions 	}
5682*c54f35caSApple OSS Distributions 	return done;
5683*c54f35caSApple OSS Distributions }
5684*c54f35caSApple OSS Distributions 
5685*c54f35caSApple OSS Distributions //*********************************************************************************
5686*c54f35caSApple OSS Distributions // [private] start_watchdog_timer
5687*c54f35caSApple OSS Distributions //*********************************************************************************
5688*c54f35caSApple OSS Distributions void
start_watchdog_timer(void)5689*c54f35caSApple OSS Distributions IOService::start_watchdog_timer( void )
5690*c54f35caSApple OSS Distributions {
5691*c54f35caSApple OSS Distributions 	int             timeout;
5692*c54f35caSApple OSS Distributions 	uint64_t        deadline;
5693*c54f35caSApple OSS Distributions 
5694*c54f35caSApple OSS Distributions 	if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5695*c54f35caSApple OSS Distributions 		return;
5696*c54f35caSApple OSS Distributions 	}
5697*c54f35caSApple OSS Distributions 
5698*c54f35caSApple OSS Distributions 	IOLockLock(fWatchdogLock);
5699*c54f35caSApple OSS Distributions 
5700*c54f35caSApple OSS Distributions 	timeout = getPMRootDomain()->getWatchdogTimeout();
5701*c54f35caSApple OSS Distributions 	clock_interval_to_deadline(timeout, kSecondScale, &deadline);
5702*c54f35caSApple OSS Distributions 	start_watchdog_timer(deadline);
5703*c54f35caSApple OSS Distributions 	IOLockUnlock(fWatchdogLock);
5704*c54f35caSApple OSS Distributions }
5705*c54f35caSApple OSS Distributions 
5706*c54f35caSApple OSS Distributions void
start_watchdog_timer(uint64_t deadline)5707*c54f35caSApple OSS Distributions IOService::start_watchdog_timer(uint64_t deadline)
5708*c54f35caSApple OSS Distributions {
5709*c54f35caSApple OSS Distributions 	IOLockAssert(fWatchdogLock, kIOLockAssertOwned);
5710*c54f35caSApple OSS Distributions 	fWatchdogDeadline = deadline;
5711*c54f35caSApple OSS Distributions 
5712*c54f35caSApple OSS Distributions 	if (!thread_call_isactive(fWatchdogTimer)) {
5713*c54f35caSApple OSS Distributions 		thread_call_enter_delayed(fWatchdogTimer, deadline);
5714*c54f35caSApple OSS Distributions 	}
5715*c54f35caSApple OSS Distributions }
5716*c54f35caSApple OSS Distributions 
5717*c54f35caSApple OSS Distributions //*********************************************************************************
5718*c54f35caSApple OSS Distributions // [private] stop_watchdog_timer
5719*c54f35caSApple OSS Distributions //*********************************************************************************
5720*c54f35caSApple OSS Distributions 
5721*c54f35caSApple OSS Distributions void
stop_watchdog_timer(void)5722*c54f35caSApple OSS Distributions IOService::stop_watchdog_timer( void )
5723*c54f35caSApple OSS Distributions {
5724*c54f35caSApple OSS Distributions 	if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5725*c54f35caSApple OSS Distributions 		return;
5726*c54f35caSApple OSS Distributions 	}
5727*c54f35caSApple OSS Distributions 
5728*c54f35caSApple OSS Distributions 	IOLockLock(fWatchdogLock);
5729*c54f35caSApple OSS Distributions 
5730*c54f35caSApple OSS Distributions 	thread_call_cancel(fWatchdogTimer);
5731*c54f35caSApple OSS Distributions 	fWatchdogDeadline = 0;
5732*c54f35caSApple OSS Distributions 
5733*c54f35caSApple OSS Distributions 	while (fBlockedArray->getCount()) {
5734*c54f35caSApple OSS Distributions 		IOService *obj = OSDynamicCast(IOService, fBlockedArray->getObject(0));
5735*c54f35caSApple OSS Distributions 		if (obj) {
5736*c54f35caSApple OSS Distributions 			PM_ERROR("WDOG:Object %s unexpected in blocked array\n", obj->fName);
5737*c54f35caSApple OSS Distributions 			fBlockedArray->removeObject(0);
5738*c54f35caSApple OSS Distributions 		}
5739*c54f35caSApple OSS Distributions 	}
5740*c54f35caSApple OSS Distributions 
5741*c54f35caSApple OSS Distributions 	IOLockUnlock(fWatchdogLock);
5742*c54f35caSApple OSS Distributions }
5743*c54f35caSApple OSS Distributions 
5744*c54f35caSApple OSS Distributions //*********************************************************************************
5745*c54f35caSApple OSS Distributions // reset_watchdog_timer
5746*c54f35caSApple OSS Distributions //*********************************************************************************
5747*c54f35caSApple OSS Distributions 
5748*c54f35caSApple OSS Distributions void
reset_watchdog_timer(IOService * blockedObject,int pendingResponseTimeout)5749*c54f35caSApple OSS Distributions IOService::reset_watchdog_timer(IOService *blockedObject, int pendingResponseTimeout)
5750*c54f35caSApple OSS Distributions {
5751*c54f35caSApple OSS Distributions 	unsigned int i;
5752*c54f35caSApple OSS Distributions 	uint64_t    deadline;
5753*c54f35caSApple OSS Distributions 	IOService *obj;
5754*c54f35caSApple OSS Distributions 
5755*c54f35caSApple OSS Distributions 	if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5756*c54f35caSApple OSS Distributions 		return;
5757*c54f35caSApple OSS Distributions 	}
5758*c54f35caSApple OSS Distributions 
5759*c54f35caSApple OSS Distributions 
5760*c54f35caSApple OSS Distributions 	IOLockLock(fWatchdogLock);
5761*c54f35caSApple OSS Distributions 	if (!fWatchdogDeadline) {
5762*c54f35caSApple OSS Distributions 		goto exit;
5763*c54f35caSApple OSS Distributions 	}
5764*c54f35caSApple OSS Distributions 
5765*c54f35caSApple OSS Distributions 	i = fBlockedArray->getNextIndexOfObject(blockedObject, 0);
5766*c54f35caSApple OSS Distributions 	if (pendingResponseTimeout == 0) {
5767*c54f35caSApple OSS Distributions 		blockedObject->fPendingResponseDeadline = 0;
5768*c54f35caSApple OSS Distributions 		if (i == (unsigned int)-1) {
5769*c54f35caSApple OSS Distributions 			goto exit;
5770*c54f35caSApple OSS Distributions 		}
5771*c54f35caSApple OSS Distributions 		fBlockedArray->removeObject(i);
5772*c54f35caSApple OSS Distributions 	} else {
5773*c54f35caSApple OSS Distributions 		// Set deadline 2secs after the expected response timeout to allow
5774*c54f35caSApple OSS Distributions 		// ack timer to handle the timeout.
5775*c54f35caSApple OSS Distributions 		clock_interval_to_deadline(pendingResponseTimeout + 2, kSecondScale, &deadline);
5776*c54f35caSApple OSS Distributions 
5777*c54f35caSApple OSS Distributions 		if (i != (unsigned int)-1) {
5778*c54f35caSApple OSS Distributions 			PM_ERROR("WDOG:Object %s is already blocked for responses. Ignoring timeout %d\n",
5779*c54f35caSApple OSS Distributions 			    fName, pendingResponseTimeout);
5780*c54f35caSApple OSS Distributions 			goto exit;
5781*c54f35caSApple OSS Distributions 		}
5782*c54f35caSApple OSS Distributions 
5783*c54f35caSApple OSS Distributions 		for (i = 0; i < fBlockedArray->getCount(); i++) {
5784*c54f35caSApple OSS Distributions 			obj = OSDynamicCast(IOService, fBlockedArray->getObject(i));
5785*c54f35caSApple OSS Distributions 			if (obj && (obj->fPendingResponseDeadline < deadline)) {
5786*c54f35caSApple OSS Distributions 				blockedObject->fPendingResponseDeadline = deadline;
5787*c54f35caSApple OSS Distributions 				fBlockedArray->setObject(i, blockedObject);
5788*c54f35caSApple OSS Distributions 				break;
5789*c54f35caSApple OSS Distributions 			}
5790*c54f35caSApple OSS Distributions 		}
5791*c54f35caSApple OSS Distributions 		if (i == fBlockedArray->getCount()) {
5792*c54f35caSApple OSS Distributions 			blockedObject->fPendingResponseDeadline = deadline;
5793*c54f35caSApple OSS Distributions 			fBlockedArray->setObject(blockedObject);
5794*c54f35caSApple OSS Distributions 		}
5795*c54f35caSApple OSS Distributions 	}
5796*c54f35caSApple OSS Distributions 
5797*c54f35caSApple OSS Distributions 	obj = OSDynamicCast(IOService, fBlockedArray->getObject(0));
5798*c54f35caSApple OSS Distributions 	if (!obj) {
5799*c54f35caSApple OSS Distributions 		int timeout = getPMRootDomain()->getWatchdogTimeout();
5800*c54f35caSApple OSS Distributions 		clock_interval_to_deadline(timeout, kSecondScale, &deadline);
5801*c54f35caSApple OSS Distributions 	} else {
5802*c54f35caSApple OSS Distributions 		deadline = obj->fPendingResponseDeadline;
5803*c54f35caSApple OSS Distributions 	}
5804*c54f35caSApple OSS Distributions 
5805*c54f35caSApple OSS Distributions 	thread_call_cancel(fWatchdogTimer);
5806*c54f35caSApple OSS Distributions 	start_watchdog_timer(deadline);
5807*c54f35caSApple OSS Distributions 
5808*c54f35caSApple OSS Distributions exit:
5809*c54f35caSApple OSS Distributions 	IOLockUnlock(fWatchdogLock);
5810*c54f35caSApple OSS Distributions }
5811*c54f35caSApple OSS Distributions 
5812*c54f35caSApple OSS Distributions 
5813*c54f35caSApple OSS Distributions //*********************************************************************************
5814*c54f35caSApple OSS Distributions // [static] watchdog_timer_expired
5815*c54f35caSApple OSS Distributions //
5816*c54f35caSApple OSS Distributions // Inside PM work loop's gate.
5817*c54f35caSApple OSS Distributions //*********************************************************************************
5818*c54f35caSApple OSS Distributions 
5819*c54f35caSApple OSS Distributions void
watchdog_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5820*c54f35caSApple OSS Distributions IOService::watchdog_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5821*c54f35caSApple OSS Distributions {
5822*c54f35caSApple OSS Distributions 	IOService * me = (IOService *) arg0;
5823*c54f35caSApple OSS Distributions 	bool expired;
5824*c54f35caSApple OSS Distributions 
5825*c54f35caSApple OSS Distributions 	IOLockLock(me->fWatchdogLock);
5826*c54f35caSApple OSS Distributions 	expired = me->fWatchdogDeadline && (me->fWatchdogDeadline <= mach_absolute_time());
5827*c54f35caSApple OSS Distributions 	IOLockUnlock(me->fWatchdogLock);
5828*c54f35caSApple OSS Distributions 	if (!expired) {
5829*c54f35caSApple OSS Distributions 		return;
5830*c54f35caSApple OSS Distributions 	}
5831*c54f35caSApple OSS Distributions 
5832*c54f35caSApple OSS Distributions 	gIOPMWatchDogThread = current_thread();
5833*c54f35caSApple OSS Distributions 	getPMRootDomain()->sleepWakeDebugTrig(true);
5834*c54f35caSApple OSS Distributions 	gIOPMWatchDogThread = NULL;
5835*c54f35caSApple OSS Distributions 	thread_call_free(me->fWatchdogTimer);
5836*c54f35caSApple OSS Distributions 	me->fWatchdogTimer = NULL;
5837*c54f35caSApple OSS Distributions 
5838*c54f35caSApple OSS Distributions 	return;
5839*c54f35caSApple OSS Distributions }
5840*c54f35caSApple OSS Distributions 
5841*c54f35caSApple OSS Distributions 
5842*c54f35caSApple OSS Distributions IOWorkLoop *
getIOPMWorkloop(void)5843*c54f35caSApple OSS Distributions IOService::getIOPMWorkloop( void )
5844*c54f35caSApple OSS Distributions {
5845*c54f35caSApple OSS Distributions 	return gIOPMWorkLoop;
5846*c54f35caSApple OSS Distributions }
5847*c54f35caSApple OSS Distributions 
5848*c54f35caSApple OSS Distributions 
5849*c54f35caSApple OSS Distributions 
5850*c54f35caSApple OSS Distributions //*********************************************************************************
5851*c54f35caSApple OSS Distributions // [private] start_ack_timer
5852*c54f35caSApple OSS Distributions //*********************************************************************************
5853*c54f35caSApple OSS Distributions 
5854*c54f35caSApple OSS Distributions void
start_ack_timer(void)5855*c54f35caSApple OSS Distributions IOService::start_ack_timer( void )
5856*c54f35caSApple OSS Distributions {
5857*c54f35caSApple OSS Distributions 	start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
5858*c54f35caSApple OSS Distributions }
5859*c54f35caSApple OSS Distributions 
5860*c54f35caSApple OSS Distributions void
start_ack_timer(UInt32 interval,UInt32 scale)5861*c54f35caSApple OSS Distributions IOService::start_ack_timer( UInt32 interval, UInt32 scale )
5862*c54f35caSApple OSS Distributions {
5863*c54f35caSApple OSS Distributions 	AbsoluteTime    deadline;
5864*c54f35caSApple OSS Distributions 	boolean_t       pending;
5865*c54f35caSApple OSS Distributions 
5866*c54f35caSApple OSS Distributions 	clock_interval_to_deadline(interval, scale, &deadline);
5867*c54f35caSApple OSS Distributions 
5868*c54f35caSApple OSS Distributions 	retain();
5869*c54f35caSApple OSS Distributions 	pending = thread_call_enter_delayed(fAckTimer, deadline);
5870*c54f35caSApple OSS Distributions 	if (pending) {
5871*c54f35caSApple OSS Distributions 		release();
5872*c54f35caSApple OSS Distributions 	}
5873*c54f35caSApple OSS Distributions }
5874*c54f35caSApple OSS Distributions 
5875*c54f35caSApple OSS Distributions //*********************************************************************************
5876*c54f35caSApple OSS Distributions // [private] stop_ack_timer
5877*c54f35caSApple OSS Distributions //*********************************************************************************
5878*c54f35caSApple OSS Distributions 
5879*c54f35caSApple OSS Distributions void
stop_ack_timer(void)5880*c54f35caSApple OSS Distributions IOService::stop_ack_timer( void )
5881*c54f35caSApple OSS Distributions {
5882*c54f35caSApple OSS Distributions 	boolean_t   pending;
5883*c54f35caSApple OSS Distributions 
5884*c54f35caSApple OSS Distributions 	pending = thread_call_cancel(fAckTimer);
5885*c54f35caSApple OSS Distributions 	if (pending) {
5886*c54f35caSApple OSS Distributions 		release();
5887*c54f35caSApple OSS Distributions 	}
5888*c54f35caSApple OSS Distributions }
5889*c54f35caSApple OSS Distributions 
5890*c54f35caSApple OSS Distributions //*********************************************************************************
5891*c54f35caSApple OSS Distributions // [static] actionAckTimerExpired
5892*c54f35caSApple OSS Distributions //
5893*c54f35caSApple OSS Distributions // Inside PM work loop's gate.
5894*c54f35caSApple OSS Distributions //*********************************************************************************
5895*c54f35caSApple OSS Distributions 
5896*c54f35caSApple OSS Distributions IOReturn
actionAckTimerExpired(OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)5897*c54f35caSApple OSS Distributions IOService::actionAckTimerExpired(
5898*c54f35caSApple OSS Distributions 	OSObject * target,
5899*c54f35caSApple OSS Distributions 	void * arg0, void * arg1,
5900*c54f35caSApple OSS Distributions 	void * arg2, void * arg3 )
5901*c54f35caSApple OSS Distributions {
5902*c54f35caSApple OSS Distributions 	IOService * me = (IOService *) target;
5903*c54f35caSApple OSS Distributions 	bool        done;
5904*c54f35caSApple OSS Distributions 
5905*c54f35caSApple OSS Distributions 	// done will be true if the timer tick unblocks the machine state,
5906*c54f35caSApple OSS Distributions 	// otherwise no need to signal the work loop.
5907*c54f35caSApple OSS Distributions 
5908*c54f35caSApple OSS Distributions 	done = me->ackTimerTick();
5909*c54f35caSApple OSS Distributions 	if (done && gIOPMWorkQueue) {
5910*c54f35caSApple OSS Distributions 		gIOPMWorkQueue->signalWorkAvailable();
5911*c54f35caSApple OSS Distributions 	}
5912*c54f35caSApple OSS Distributions 
5913*c54f35caSApple OSS Distributions 	return kIOReturnSuccess;
5914*c54f35caSApple OSS Distributions }
5915*c54f35caSApple OSS Distributions 
5916*c54f35caSApple OSS Distributions //*********************************************************************************
5917*c54f35caSApple OSS Distributions // ack_timer_expired
5918*c54f35caSApple OSS Distributions //
5919*c54f35caSApple OSS Distributions // Thread call function. Holds a retain while the callout is in flight.
5920*c54f35caSApple OSS Distributions //*********************************************************************************
5921*c54f35caSApple OSS Distributions 
5922*c54f35caSApple OSS Distributions void
ack_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5923*c54f35caSApple OSS Distributions IOService::ack_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5924*c54f35caSApple OSS Distributions {
5925*c54f35caSApple OSS Distributions 	IOService * me = (IOService *) arg0;
5926*c54f35caSApple OSS Distributions 
5927*c54f35caSApple OSS Distributions 	if (gIOPMWorkLoop) {
5928*c54f35caSApple OSS Distributions 		gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
5929*c54f35caSApple OSS Distributions 	}
5930*c54f35caSApple OSS Distributions 	me->release();
5931*c54f35caSApple OSS Distributions }
5932*c54f35caSApple OSS Distributions 
5933*c54f35caSApple OSS Distributions 
5934*c54f35caSApple OSS Distributions // MARK: -
5935*c54f35caSApple OSS Distributions // MARK: Client Messaging
5936*c54f35caSApple OSS Distributions 
5937*c54f35caSApple OSS Distributions //*********************************************************************************
5938*c54f35caSApple OSS Distributions // [private] tellSystemCapabilityChange
5939*c54f35caSApple OSS Distributions //*********************************************************************************
5940*c54f35caSApple OSS Distributions 
5941*c54f35caSApple OSS Distributions void
tellSystemCapabilityChange(uint32_t nextMS)5942*c54f35caSApple OSS Distributions IOService::tellSystemCapabilityChange( uint32_t nextMS )
5943*c54f35caSApple OSS Distributions {
5944*c54f35caSApple OSS Distributions 	assert(IS_ROOT_DOMAIN);
5945*c54f35caSApple OSS Distributions 
5946*c54f35caSApple OSS Distributions 	MS_PUSH( nextMS );
5947*c54f35caSApple OSS Distributions 	fMachineState       = kIOPM_TellCapabilityChangeDone;
5948*c54f35caSApple OSS Distributions 	fOutOfBandMessage   = kIOMessageSystemCapabilityChange;
5949*c54f35caSApple OSS Distributions 
5950*c54f35caSApple OSS Distributions 	if (fIsPreChange) {
5951*c54f35caSApple OSS Distributions 		// Notify app first on pre-change.
5952*c54f35caSApple OSS Distributions 		fOutOfBandParameter = kNotifyCapabilityChangeApps;
5953*c54f35caSApple OSS Distributions 	} else {
5954*c54f35caSApple OSS Distributions 		// Notify kernel clients first on post-change.
5955*c54f35caSApple OSS Distributions 		fOutOfBandParameter = kNotifyCapabilityChangePriority;
5956*c54f35caSApple OSS Distributions 	}
5957*c54f35caSApple OSS Distributions 
5958*c54f35caSApple OSS Distributions 	tellClientsWithResponse( fOutOfBandMessage );
5959*c54f35caSApple OSS Distributions }
5960*c54f35caSApple OSS Distributions 
5961*c54f35caSApple OSS Distributions //*********************************************************************************
5962*c54f35caSApple OSS Distributions // [public] askChangeDown
5963*c54f35caSApple OSS Distributions //
5964*c54f35caSApple OSS Distributions // Ask registered applications and kernel clients if we can change to a lower
5965*c54f35caSApple OSS Distributions // power state.
5966*c54f35caSApple OSS Distributions //
5967*c54f35caSApple OSS Distributions // Subclass can override this to send a different message type.  Parameter is
5968*c54f35caSApple OSS Distributions // the destination state number.
5969*c54f35caSApple OSS Distributions //
5970*c54f35caSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
5971*c54f35caSApple OSS Distributions //*********************************************************************************
5972*c54f35caSApple OSS Distributions 
5973*c54f35caSApple OSS Distributions bool
askChangeDown(unsigned long stateNum)5974*c54f35caSApple OSS Distributions IOService::askChangeDown( unsigned long stateNum )
5975*c54f35caSApple OSS Distributions {
5976*c54f35caSApple OSS Distributions 	return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
5977*c54f35caSApple OSS Distributions }
5978*c54f35caSApple OSS Distributions 
5979*c54f35caSApple OSS Distributions //*********************************************************************************
5980*c54f35caSApple OSS Distributions // [private] tellChangeDown1
5981*c54f35caSApple OSS Distributions //
5982*c54f35caSApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
5983*c54f35caSApple OSS Distributions // dropping power.
5984*c54f35caSApple OSS Distributions //
5985*c54f35caSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
5986*c54f35caSApple OSS Distributions //*********************************************************************************
5987*c54f35caSApple OSS Distributions 
5988*c54f35caSApple OSS Distributions bool
tellChangeDown1(unsigned long stateNum)5989*c54f35caSApple OSS Distributions IOService::tellChangeDown1( unsigned long stateNum )
5990*c54f35caSApple OSS Distributions {
5991*c54f35caSApple OSS Distributions 	fOutOfBandParameter = kNotifyApps;
5992*c54f35caSApple OSS Distributions 	return tellChangeDown(stateNum);
5993*c54f35caSApple OSS Distributions }
5994*c54f35caSApple OSS Distributions 
5995*c54f35caSApple OSS Distributions //*********************************************************************************
5996*c54f35caSApple OSS Distributions // [private] tellChangeDown2
5997*c54f35caSApple OSS Distributions //
5998*c54f35caSApple OSS Distributions // Notify priority clients that we are definitely dropping power.
5999*c54f35caSApple OSS Distributions //
6000*c54f35caSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6001*c54f35caSApple OSS Distributions //*********************************************************************************
6002*c54f35caSApple OSS Distributions 
6003*c54f35caSApple OSS Distributions bool
tellChangeDown2(unsigned long stateNum)6004*c54f35caSApple OSS Distributions IOService::tellChangeDown2( unsigned long stateNum )
6005*c54f35caSApple OSS Distributions {
6006*c54f35caSApple OSS Distributions 	fOutOfBandParameter = kNotifyPriority;
6007*c54f35caSApple OSS Distributions 	return tellChangeDown(stateNum);
6008*c54f35caSApple OSS Distributions }
6009*c54f35caSApple OSS Distributions 
6010*c54f35caSApple OSS Distributions //*********************************************************************************
6011*c54f35caSApple OSS Distributions // [public] tellChangeDown
6012*c54f35caSApple OSS Distributions //
6013*c54f35caSApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
6014*c54f35caSApple OSS Distributions // dropping power.
6015*c54f35caSApple OSS Distributions //
6016*c54f35caSApple OSS Distributions // Subclass can override this to send a different message type.  Parameter is
6017*c54f35caSApple OSS Distributions // the destination state number.
6018*c54f35caSApple OSS Distributions //
6019*c54f35caSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6020*c54f35caSApple OSS Distributions //*********************************************************************************
6021*c54f35caSApple OSS Distributions 
6022*c54f35caSApple OSS Distributions bool
tellChangeDown(unsigned long stateNum)6023*c54f35caSApple OSS Distributions IOService::tellChangeDown( unsigned long stateNum )
6024*c54f35caSApple OSS Distributions {
6025*c54f35caSApple OSS Distributions 	return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
6026*c54f35caSApple OSS Distributions }
6027*c54f35caSApple OSS Distributions 
6028*c54f35caSApple OSS Distributions //*********************************************************************************
6029*c54f35caSApple OSS Distributions // cleanClientResponses
6030*c54f35caSApple OSS Distributions //
6031*c54f35caSApple OSS Distributions //*********************************************************************************
6032*c54f35caSApple OSS Distributions 
6033*c54f35caSApple OSS Distributions static void
logAppTimeouts(OSObject * object,void * arg)6034*c54f35caSApple OSS Distributions logAppTimeouts( OSObject * object, void * arg )
6035*c54f35caSApple OSS Distributions {
6036*c54f35caSApple OSS Distributions 	IOPMInterestContext *   context = (IOPMInterestContext *) arg;
6037*c54f35caSApple OSS Distributions 	OSObject *              flag;
6038*c54f35caSApple OSS Distributions 	unsigned int            clientIndex;
6039*c54f35caSApple OSS Distributions 	int                     pid = 0;
6040*c54f35caSApple OSS Distributions 	char                    name[128];
6041*c54f35caSApple OSS Distributions 
6042*c54f35caSApple OSS Distributions 	if (OSDynamicCast(_IOServiceInterestNotifier, object)) {
6043*c54f35caSApple OSS Distributions 		// Discover the 'counter' value or index assigned to this client
6044*c54f35caSApple OSS Distributions 		// when it was notified, by searching for the array index of the
6045*c54f35caSApple OSS Distributions 		// client in an array holding the cached interested clients.
6046*c54f35caSApple OSS Distributions 
6047*c54f35caSApple OSS Distributions 		clientIndex = context->notifyClients->getNextIndexOfObject(object, 0);
6048*c54f35caSApple OSS Distributions 
6049*c54f35caSApple OSS Distributions 		if ((clientIndex != (unsigned int) -1) &&
6050*c54f35caSApple OSS Distributions 		    (flag = context->responseArray->getObject(clientIndex)) &&
6051*c54f35caSApple OSS Distributions 		    (flag != kOSBooleanTrue)) {
6052*c54f35caSApple OSS Distributions 			OSNumber *clientID = copyClientIDForNotification(object, context);
6053*c54f35caSApple OSS Distributions 
6054*c54f35caSApple OSS Distributions 			name[0] = '\0';
6055*c54f35caSApple OSS Distributions 			if (clientID) {
6056*c54f35caSApple OSS Distributions 				pid = clientID->unsigned32BitValue();
6057*c54f35caSApple OSS Distributions 				proc_name(pid, name, sizeof(name));
6058*c54f35caSApple OSS Distributions 				clientID->release();
6059*c54f35caSApple OSS Distributions 			}
6060*c54f35caSApple OSS Distributions 
6061*c54f35caSApple OSS Distributions 			PM_ERROR("PM notification timeout (pid %d, %s)\n", pid, name);
6062*c54f35caSApple OSS Distributions 
6063*c54f35caSApple OSS Distributions 			// TODO: record message type if possible
6064*c54f35caSApple OSS Distributions 			IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
6065*c54f35caSApple OSS Distributions 				gIOPMStatsResponseTimedOut,
6066*c54f35caSApple OSS Distributions 				name, 0, (30 * 1000), pid, object);
6067*c54f35caSApple OSS Distributions 		}
6068*c54f35caSApple OSS Distributions 	}
6069*c54f35caSApple OSS Distributions }
6070*c54f35caSApple OSS Distributions 
6071*c54f35caSApple OSS Distributions void
cleanClientResponses(bool logErrors)6072*c54f35caSApple OSS Distributions IOService::cleanClientResponses( bool logErrors )
6073*c54f35caSApple OSS Distributions {
6074*c54f35caSApple OSS Distributions 	if (logErrors && fResponseArray) {
6075*c54f35caSApple OSS Distributions 		switch (fOutOfBandParameter) {
6076*c54f35caSApple OSS Distributions 		case kNotifyApps:
6077*c54f35caSApple OSS Distributions 		case kNotifyCapabilityChangeApps:
6078*c54f35caSApple OSS Distributions 			if (fNotifyClientArray) {
6079*c54f35caSApple OSS Distributions 				IOPMInterestContext context;
6080*c54f35caSApple OSS Distributions 
6081*c54f35caSApple OSS Distributions 				context.responseArray    = fResponseArray;
6082*c54f35caSApple OSS Distributions 				context.notifyClients    = fNotifyClientArray;
6083*c54f35caSApple OSS Distributions 				context.serialNumber     = fSerialNumber;
6084*c54f35caSApple OSS Distributions 				context.messageType      = kIOMessageCopyClientID;
6085*c54f35caSApple OSS Distributions 				context.notifyType       = kNotifyApps;
6086*c54f35caSApple OSS Distributions 				context.isPreChange      = fIsPreChange;
6087*c54f35caSApple OSS Distributions 				context.enableTracing    = false;
6088*c54f35caSApple OSS Distributions 				context.us               = this;
6089*c54f35caSApple OSS Distributions 				context.maxTimeRequested = 0;
6090*c54f35caSApple OSS Distributions 				context.stateNumber      = fHeadNotePowerState;
6091*c54f35caSApple OSS Distributions 				context.stateFlags       = fHeadNotePowerArrayEntry->capabilityFlags;
6092*c54f35caSApple OSS Distributions 				context.changeFlags      = fHeadNoteChangeFlags;
6093*c54f35caSApple OSS Distributions 
6094*c54f35caSApple OSS Distributions 				applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &context);
6095*c54f35caSApple OSS Distributions 			}
6096*c54f35caSApple OSS Distributions 			break;
6097*c54f35caSApple OSS Distributions 
6098*c54f35caSApple OSS Distributions 		default:
6099*c54f35caSApple OSS Distributions 			// kNotifyPriority, kNotifyCapabilityChangePriority
6100*c54f35caSApple OSS Distributions 			// TODO: identify the priority client that has not acked
6101*c54f35caSApple OSS Distributions 			PM_ERROR("PM priority notification timeout\n");
6102*c54f35caSApple OSS Distributions 			if (gIOKitDebug & kIOLogDebugPower) {
6103*c54f35caSApple OSS Distributions 				panic("PM priority notification timeout");
6104*c54f35caSApple OSS Distributions 			}
6105*c54f35caSApple OSS Distributions 			break;
6106*c54f35caSApple OSS Distributions 		}
6107*c54f35caSApple OSS Distributions 	}
6108*c54f35caSApple OSS Distributions 
6109*c54f35caSApple OSS Distributions 	if (IS_ROOT_DOMAIN) {
6110*c54f35caSApple OSS Distributions 		getPMRootDomain()->reset_watchdog_timer(this, 0);
6111*c54f35caSApple OSS Distributions 	}
6112*c54f35caSApple OSS Distributions 	if (fResponseArray) {
6113*c54f35caSApple OSS Distributions 		fResponseArray->release();
6114*c54f35caSApple OSS Distributions 		fResponseArray = NULL;
6115*c54f35caSApple OSS Distributions 	}
6116*c54f35caSApple OSS Distributions 	if (fNotifyClientArray) {
6117*c54f35caSApple OSS Distributions 		fNotifyClientArray->release();
6118*c54f35caSApple OSS Distributions 		fNotifyClientArray = NULL;
6119*c54f35caSApple OSS Distributions 	}
6120*c54f35caSApple OSS Distributions }
6121*c54f35caSApple OSS Distributions 
6122*c54f35caSApple OSS Distributions //*********************************************************************************
6123*c54f35caSApple OSS Distributions // [protected] tellClientsWithResponse
6124*c54f35caSApple OSS Distributions //
6125*c54f35caSApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
6126*c54f35caSApple OSS Distributions // dropping power.
6127*c54f35caSApple OSS Distributions //
6128*c54f35caSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6129*c54f35caSApple OSS Distributions //*********************************************************************************
6130*c54f35caSApple OSS Distributions 
6131*c54f35caSApple OSS Distributions bool
tellClientsWithResponse(int messageType)6132*c54f35caSApple OSS Distributions IOService::tellClientsWithResponse( int messageType )
6133*c54f35caSApple OSS Distributions {
6134*c54f35caSApple OSS Distributions 	IOPMInterestContext     context;
6135*c54f35caSApple OSS Distributions 	bool                    isRootDomain = IS_ROOT_DOMAIN;
6136*c54f35caSApple OSS Distributions 	uint32_t                maxTimeOut = kMaxTimeRequested;
6137*c54f35caSApple OSS Distributions 
6138*c54f35caSApple OSS Distributions 	PM_ASSERT_IN_GATE();
6139*c54f35caSApple OSS Distributions 	assert( fResponseArray == NULL );
6140*c54f35caSApple OSS Distributions 	assert( fNotifyClientArray == NULL );
6141*c54f35caSApple OSS Distributions 
6142*c54f35caSApple OSS Distributions 	RD_LOG("tellClientsWithResponse( %s, %s )\n", getIOMessageString(messageType),
6143*c54f35caSApple OSS Distributions 	    getNotificationPhaseString(fOutOfBandParameter));
6144*c54f35caSApple OSS Distributions 
6145*c54f35caSApple OSS Distributions 	fResponseArray = OSArray::withCapacity( 1 );
6146*c54f35caSApple OSS Distributions 	if (!fResponseArray) {
6147*c54f35caSApple OSS Distributions 		goto exit;
6148*c54f35caSApple OSS Distributions 	}
6149*c54f35caSApple OSS Distributions 
6150*c54f35caSApple OSS Distributions 	fResponseArray->setCapacityIncrement(8);
6151*c54f35caSApple OSS Distributions 	if (++fSerialNumber == 0) {
6152*c54f35caSApple OSS Distributions 		fSerialNumber++;
6153*c54f35caSApple OSS Distributions 	}
6154*c54f35caSApple OSS Distributions 
6155*c54f35caSApple OSS Distributions 	context.responseArray    = fResponseArray;
6156*c54f35caSApple OSS Distributions 	context.notifyClients    = NULL;
6157*c54f35caSApple OSS Distributions 	context.serialNumber     = fSerialNumber;
6158*c54f35caSApple OSS Distributions 	context.messageType      = messageType;
6159*c54f35caSApple OSS Distributions 	context.notifyType       = fOutOfBandParameter;
6160*c54f35caSApple OSS Distributions 	context.skippedInDark    = 0;
6161*c54f35caSApple OSS Distributions 	context.notSkippedInDark = 0;
6162*c54f35caSApple OSS Distributions 	context.isPreChange      = fIsPreChange;
6163*c54f35caSApple OSS Distributions 	context.enableTracing    = false;
6164*c54f35caSApple OSS Distributions 	context.us               = this;
6165*c54f35caSApple OSS Distributions 	context.maxTimeRequested = 0;
6166*c54f35caSApple OSS Distributions 	context.stateNumber      = fHeadNotePowerState;
6167*c54f35caSApple OSS Distributions 	context.stateFlags       = fHeadNotePowerArrayEntry->capabilityFlags;
6168*c54f35caSApple OSS Distributions 	context.changeFlags      = fHeadNoteChangeFlags;
6169*c54f35caSApple OSS Distributions 	context.messageFilter    = (isRootDomain) ?
6170*c54f35caSApple OSS Distributions 	    OSMemberFunctionCast(
6171*c54f35caSApple OSS Distributions 		IOPMMessageFilter,
6172*c54f35caSApple OSS Distributions 		(IOPMrootDomain *)this,
6173*c54f35caSApple OSS Distributions 		&IOPMrootDomain::systemMessageFilter) : NULL;
6174*c54f35caSApple OSS Distributions 
6175*c54f35caSApple OSS Distributions 	switch (fOutOfBandParameter) {
6176*c54f35caSApple OSS Distributions 	case kNotifyApps:
6177*c54f35caSApple OSS Distributions 		applyToInterested( gIOAppPowerStateInterest,
6178*c54f35caSApple OSS Distributions 		    pmTellAppWithResponse, (void *) &context );
6179*c54f35caSApple OSS Distributions 
6180*c54f35caSApple OSS Distributions 		if (isRootDomain &&
6181*c54f35caSApple OSS Distributions 		    (fMachineState != kIOPM_OurChangeTellClientsPowerDown) &&
6182*c54f35caSApple OSS Distributions 		    (fMachineState != kIOPM_SyncTellClientsPowerDown) &&
6183*c54f35caSApple OSS Distributions 		    (context.messageType != kIOPMMessageLastCallBeforeSleep)) {
6184*c54f35caSApple OSS Distributions 			// Notify capability app for tellChangeDown1()
6185*c54f35caSApple OSS Distributions 			// but not for askChangeDown().
6186*c54f35caSApple OSS Distributions 			context.notifyType  = kNotifyCapabilityChangeApps;
6187*c54f35caSApple OSS Distributions 			context.messageType = kIOMessageSystemCapabilityChange;
6188*c54f35caSApple OSS Distributions 			applyToInterested( gIOAppPowerStateInterest,
6189*c54f35caSApple OSS Distributions 			    pmTellCapabilityAppWithResponse, (void *) &context );
6190*c54f35caSApple OSS Distributions 			context.notifyType  = fOutOfBandParameter;
6191*c54f35caSApple OSS Distributions 			context.messageType = messageType;
6192*c54f35caSApple OSS Distributions 		}
6193*c54f35caSApple OSS Distributions 		if (context.messageType == kIOMessageCanSystemSleep) {
6194*c54f35caSApple OSS Distributions 			maxTimeOut = kCanSleepMaxTimeReq;
6195*c54f35caSApple OSS Distributions 			if (gSleepAckTimeout) {
6196*c54f35caSApple OSS Distributions 				maxTimeOut = (gSleepAckTimeout * us_per_s);
6197*c54f35caSApple OSS Distributions 			}
6198*c54f35caSApple OSS Distributions 		}
6199*c54f35caSApple OSS Distributions 		if (context.messageType == kIOMessageSystemWillSleep) {
6200*c54f35caSApple OSS Distributions 			maxTimeOut = kWillSleepMaxTimeReq;
6201*c54f35caSApple OSS Distributions 			if (gSleepAckTimeout) {
6202*c54f35caSApple OSS Distributions 				maxTimeOut = (gSleepAckTimeout * us_per_s);
6203*c54f35caSApple OSS Distributions 			}
6204*c54f35caSApple OSS Distributions 		}
6205*c54f35caSApple OSS Distributions 		context.maxTimeRequested = maxTimeOut;
6206*c54f35caSApple OSS Distributions 		context.enableTracing = isRootDomain;
6207*c54f35caSApple OSS Distributions 		applyToInterested( gIOGeneralInterest,
6208*c54f35caSApple OSS Distributions 		    pmTellClientWithResponse, (void *) &context );
6209*c54f35caSApple OSS Distributions 
6210*c54f35caSApple OSS Distributions 		break;
6211*c54f35caSApple OSS Distributions 
6212*c54f35caSApple OSS Distributions 	case kNotifyPriority:
6213*c54f35caSApple OSS Distributions 		context.enableTracing = isRootDomain;
6214*c54f35caSApple OSS Distributions 		applyToInterested( gIOPriorityPowerStateInterest,
6215*c54f35caSApple OSS Distributions 		    pmTellClientWithResponse, (void *) &context );
6216*c54f35caSApple OSS Distributions 
6217*c54f35caSApple OSS Distributions 		if (isRootDomain) {
6218*c54f35caSApple OSS Distributions 			// Notify capability clients for tellChangeDown2().
6219*c54f35caSApple OSS Distributions 			context.notifyType  = kNotifyCapabilityChangePriority;
6220*c54f35caSApple OSS Distributions 			context.messageType = kIOMessageSystemCapabilityChange;
6221*c54f35caSApple OSS Distributions 			applyToInterested( gIOPriorityPowerStateInterest,
6222*c54f35caSApple OSS Distributions 			    pmTellCapabilityClientWithResponse, (void *) &context );
6223*c54f35caSApple OSS Distributions 		}
6224*c54f35caSApple OSS Distributions 		break;
6225*c54f35caSApple OSS Distributions 
6226*c54f35caSApple OSS Distributions 	case kNotifyCapabilityChangeApps:
6227*c54f35caSApple OSS Distributions 		context.enableTracing = isRootDomain;
6228*c54f35caSApple OSS Distributions 		applyToInterested( gIOAppPowerStateInterest,
6229*c54f35caSApple OSS Distributions 		    pmTellCapabilityAppWithResponse, (void *) &context );
6230*c54f35caSApple OSS Distributions 		if (context.messageType == kIOMessageCanSystemSleep) {
6231*c54f35caSApple OSS Distributions 			maxTimeOut = kCanSleepMaxTimeReq;
6232*c54f35caSApple OSS Distributions 			if (gSleepAckTimeout) {
6233*c54f35caSApple OSS Distributions 				maxTimeOut = (gSleepAckTimeout * us_per_s);
6234*c54f35caSApple OSS Distributions 			}
6235*c54f35caSApple OSS Distributions 		}
6236*c54f35caSApple OSS Distributions 		context.maxTimeRequested = maxTimeOut;
6237*c54f35caSApple OSS Distributions 		break;
6238*c54f35caSApple OSS Distributions 
6239*c54f35caSApple OSS Distributions 	case kNotifyCapabilityChangePriority:
6240*c54f35caSApple OSS Distributions 		context.enableTracing = isRootDomain;
6241*c54f35caSApple OSS Distributions 		applyToInterested( gIOPriorityPowerStateInterest,
6242*c54f35caSApple OSS Distributions 		    pmTellCapabilityClientWithResponse, (void *) &context );
6243*c54f35caSApple OSS Distributions 		break;
6244*c54f35caSApple OSS Distributions 	}
6245*c54f35caSApple OSS Distributions 	fNotifyClientArray = context.notifyClients;
6246*c54f35caSApple OSS Distributions 
6247*c54f35caSApple OSS Distributions 	if (context.skippedInDark) {
6248*c54f35caSApple OSS Distributions 		IOLog("tellClientsWithResponse(%s, %s) %d of %d skipped in dark\n",
6249*c54f35caSApple OSS Distributions 		    getIOMessageString(messageType), getNotificationPhaseString(fOutOfBandParameter),
6250*c54f35caSApple OSS Distributions 		    context.skippedInDark, context.skippedInDark + context.notSkippedInDark);
6251*c54f35caSApple OSS Distributions 	}
6252*c54f35caSApple OSS Distributions 
6253*c54f35caSApple OSS Distributions 	// do we have to wait for somebody?
6254*c54f35caSApple OSS Distributions 	if (!checkForDone()) {
6255*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogStartAckTimer, context.maxTimeRequested, 0);
6256*c54f35caSApple OSS Distributions 		if (context.enableTracing) {
6257*c54f35caSApple OSS Distributions 			getPMRootDomain()->traceDetail(context.messageType, 0, context.maxTimeRequested / 1000);
6258*c54f35caSApple OSS Distributions 			getPMRootDomain()->reset_watchdog_timer(this, context.maxTimeRequested / USEC_PER_SEC + 1);
6259*c54f35caSApple OSS Distributions 		}
6260*c54f35caSApple OSS Distributions 		start_ack_timer( context.maxTimeRequested / 1000, kMillisecondScale );
6261*c54f35caSApple OSS Distributions 		return false;
6262*c54f35caSApple OSS Distributions 	}
6263*c54f35caSApple OSS Distributions 
6264*c54f35caSApple OSS Distributions exit:
6265*c54f35caSApple OSS Distributions 	// everybody responded
6266*c54f35caSApple OSS Distributions 	if (fResponseArray) {
6267*c54f35caSApple OSS Distributions 		fResponseArray->release();
6268*c54f35caSApple OSS Distributions 		fResponseArray = NULL;
6269*c54f35caSApple OSS Distributions 	}
6270*c54f35caSApple OSS Distributions 	if (fNotifyClientArray) {
6271*c54f35caSApple OSS Distributions 		fNotifyClientArray->release();
6272*c54f35caSApple OSS Distributions 		fNotifyClientArray = NULL;
6273*c54f35caSApple OSS Distributions 	}
6274*c54f35caSApple OSS Distributions 
6275*c54f35caSApple OSS Distributions 	return true;
6276*c54f35caSApple OSS Distributions }
6277*c54f35caSApple OSS Distributions 
6278*c54f35caSApple OSS Distributions //*********************************************************************************
6279*c54f35caSApple OSS Distributions // [static private] pmTellAppWithResponse
6280*c54f35caSApple OSS Distributions //
6281*c54f35caSApple OSS Distributions // We send a message to an application, and we expect a response, so we compute a
6282*c54f35caSApple OSS Distributions // cookie we can identify the response with.
6283*c54f35caSApple OSS Distributions //*********************************************************************************
6284*c54f35caSApple OSS Distributions 
6285*c54f35caSApple OSS Distributions void
pmTellAppWithResponse(OSObject * object,void * arg)6286*c54f35caSApple OSS Distributions IOService::pmTellAppWithResponse( OSObject * object, void * arg )
6287*c54f35caSApple OSS Distributions {
6288*c54f35caSApple OSS Distributions 	IOPMInterestContext *   context = (IOPMInterestContext *) arg;
6289*c54f35caSApple OSS Distributions 	IOServicePM *           pwrMgt = context->us->pwrMgt;
6290*c54f35caSApple OSS Distributions 	uint32_t                msgIndex, msgRef, msgType;
6291*c54f35caSApple OSS Distributions 	OSNumber                *clientID = NULL;
6292*c54f35caSApple OSS Distributions 	proc_t                  proc = NULL;
6293*c54f35caSApple OSS Distributions 	boolean_t               proc_suspended = FALSE;
6294*c54f35caSApple OSS Distributions 	OSObject *              waitForReply = kOSBooleanTrue;
6295*c54f35caSApple OSS Distributions #if LOG_APP_RESPONSE_TIMES
6296*c54f35caSApple OSS Distributions 	AbsoluteTime            now;
6297*c54f35caSApple OSS Distributions #endif
6298*c54f35caSApple OSS Distributions 
6299*c54f35caSApple OSS Distributions 	if (!OSDynamicCast(_IOServiceInterestNotifier, object)) {
6300*c54f35caSApple OSS Distributions 		return;
6301*c54f35caSApple OSS Distributions 	}
6302*c54f35caSApple OSS Distributions 
6303*c54f35caSApple OSS Distributions 	if (context->us == getPMRootDomain()) {
6304*c54f35caSApple OSS Distributions 		if ((clientID = copyClientIDForNotification(object, context))) {
6305*c54f35caSApple OSS Distributions 			uint32_t clientPID = clientID->unsigned32BitValue();
6306*c54f35caSApple OSS Distributions 			clientID->release();
6307*c54f35caSApple OSS Distributions 			proc = proc_find(clientPID);
6308*c54f35caSApple OSS Distributions 
6309*c54f35caSApple OSS Distributions 			if (proc) {
6310*c54f35caSApple OSS Distributions 				proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6311*c54f35caSApple OSS Distributions 				if (proc_suspended) {
6312*c54f35caSApple OSS Distributions 					logClientIDForNotification(object, context, "PMTellAppWithResponse - Suspended");
6313*c54f35caSApple OSS Distributions 				} else if (getPMRootDomain()->isAOTMode() && get_task_suspended((task_t) proc_task(proc))) {
6314*c54f35caSApple OSS Distributions 					proc_suspended = true;
6315*c54f35caSApple OSS Distributions 					context->skippedInDark++;
6316*c54f35caSApple OSS Distributions 				}
6317*c54f35caSApple OSS Distributions 				proc_rele(proc);
6318*c54f35caSApple OSS Distributions 				if (proc_suspended) {
6319*c54f35caSApple OSS Distributions 					return;
6320*c54f35caSApple OSS Distributions 				}
6321*c54f35caSApple OSS Distributions 			}
6322*c54f35caSApple OSS Distributions 		}
6323*c54f35caSApple OSS Distributions 	}
6324*c54f35caSApple OSS Distributions 
6325*c54f35caSApple OSS Distributions 	if (context->messageFilter &&
6326*c54f35caSApple OSS Distributions 	    !context->messageFilter(context->us, object, context, NULL, &waitForReply)) {
6327*c54f35caSApple OSS Distributions 		if (kIOLogDebugPower & gIOKitDebug) {
6328*c54f35caSApple OSS Distributions 			logClientIDForNotification(object, context, "DROP App");
6329*c54f35caSApple OSS Distributions 		}
6330*c54f35caSApple OSS Distributions 		return;
6331*c54f35caSApple OSS Distributions 	}
6332*c54f35caSApple OSS Distributions 	context->notSkippedInDark++;
6333*c54f35caSApple OSS Distributions 
6334*c54f35caSApple OSS Distributions 	// Create client array (for tracking purposes) only if the service
6335*c54f35caSApple OSS Distributions 	// has app clients. Usually only root domain does.
6336*c54f35caSApple OSS Distributions 	if (NULL == context->notifyClients) {
6337*c54f35caSApple OSS Distributions 		context->notifyClients = OSArray::withCapacity( 32 );
6338*c54f35caSApple OSS Distributions 	}
6339*c54f35caSApple OSS Distributions 
6340*c54f35caSApple OSS Distributions 	msgType  = context->messageType;
6341*c54f35caSApple OSS Distributions 	msgIndex = context->responseArray->getCount();
6342*c54f35caSApple OSS Distributions 	msgRef   = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6343*c54f35caSApple OSS Distributions 
6344*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
6345*c54f35caSApple OSS Distributions 	if (kIOLogDebugPower & gIOKitDebug) {
6346*c54f35caSApple OSS Distributions 		logClientIDForNotification(object, context, "MESG App");
6347*c54f35caSApple OSS Distributions 	}
6348*c54f35caSApple OSS Distributions 
6349*c54f35caSApple OSS Distributions 	if (waitForReply == kOSBooleanTrue) {
6350*c54f35caSApple OSS Distributions 		OSNumber * num;
6351*c54f35caSApple OSS Distributions 		clock_get_uptime(&now);
6352*c54f35caSApple OSS Distributions 		num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
6353*c54f35caSApple OSS Distributions 		if (num) {
6354*c54f35caSApple OSS Distributions 			context->responseArray->setObject(msgIndex, num);
6355*c54f35caSApple OSS Distributions 			num->release();
6356*c54f35caSApple OSS Distributions 		} else {
6357*c54f35caSApple OSS Distributions 			context->responseArray->setObject(msgIndex, kOSBooleanFalse);
6358*c54f35caSApple OSS Distributions 		}
6359*c54f35caSApple OSS Distributions 	} else {
6360*c54f35caSApple OSS Distributions 		context->responseArray->setObject(msgIndex, kOSBooleanTrue);
6361*c54f35caSApple OSS Distributions 		if (kIOLogDebugPower & gIOKitDebug) {
6362*c54f35caSApple OSS Distributions 			logClientIDForNotification(object, context, "App response ignored");
6363*c54f35caSApple OSS Distributions 		}
6364*c54f35caSApple OSS Distributions 	}
6365*c54f35caSApple OSS Distributions 
6366*c54f35caSApple OSS Distributions 	if (context->notifyClients) {
6367*c54f35caSApple OSS Distributions 		context->notifyClients->setObject(msgIndex, object);
6368*c54f35caSApple OSS Distributions 	}
6369*c54f35caSApple OSS Distributions 
6370*c54f35caSApple OSS Distributions 	context->us->messageClient(msgType, object, (void *)(uintptr_t) msgRef);
6371*c54f35caSApple OSS Distributions }
6372*c54f35caSApple OSS Distributions 
6373*c54f35caSApple OSS Distributions //*********************************************************************************
6374*c54f35caSApple OSS Distributions // [static private] pmTellClientWithResponse
6375*c54f35caSApple OSS Distributions //
6376*c54f35caSApple OSS Distributions // We send a message to an in-kernel client, and we expect a response,
6377*c54f35caSApple OSS Distributions // so we compute a cookie we can identify the response with.
6378*c54f35caSApple OSS Distributions //*********************************************************************************
6379*c54f35caSApple OSS Distributions 
6380*c54f35caSApple OSS Distributions void
pmTellClientWithResponse(OSObject * object,void * arg)6381*c54f35caSApple OSS Distributions IOService::pmTellClientWithResponse( OSObject * object, void * arg )
6382*c54f35caSApple OSS Distributions {
6383*c54f35caSApple OSS Distributions 	IOPowerStateChangeNotification  notify;
6384*c54f35caSApple OSS Distributions 	IOPMInterestContext *           context = (IOPMInterestContext *) arg;
6385*c54f35caSApple OSS Distributions 	OSObject *                      replied = kOSBooleanTrue;
6386*c54f35caSApple OSS Distributions 	_IOServiceInterestNotifier *    notifier;
6387*c54f35caSApple OSS Distributions 	uint32_t                        msgIndex, msgRef, msgType;
6388*c54f35caSApple OSS Distributions 	IOReturn                        retCode;
6389*c54f35caSApple OSS Distributions 	AbsoluteTime                    start, end;
6390*c54f35caSApple OSS Distributions 	uint64_t                        nsec;
6391*c54f35caSApple OSS Distributions 	bool                            enableTracing;
6392*c54f35caSApple OSS Distributions 
6393*c54f35caSApple OSS Distributions 	if (context->messageFilter &&
6394*c54f35caSApple OSS Distributions 	    !context->messageFilter(context->us, object, context, NULL, NULL)) {
6395*c54f35caSApple OSS Distributions 		getPMRootDomain()->traceFilteredNotification(object);
6396*c54f35caSApple OSS Distributions 		return;
6397*c54f35caSApple OSS Distributions 	}
6398*c54f35caSApple OSS Distributions 
6399*c54f35caSApple OSS Distributions 	// Besides interest notifiers this applier function can also be invoked against
6400*c54f35caSApple OSS Distributions 	// IOService clients of context->us, so notifier can be NULL. But for tracing
6401*c54f35caSApple OSS Distributions 	// purposes the IOService clients can be ignored but each will still consume
6402*c54f35caSApple OSS Distributions 	// an entry in the responseArray and also advance msgIndex.
6403*c54f35caSApple OSS Distributions 	notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
6404*c54f35caSApple OSS Distributions 	msgType  = context->messageType;
6405*c54f35caSApple OSS Distributions 	msgIndex = context->responseArray->getCount();
6406*c54f35caSApple OSS Distributions 	msgRef   = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6407*c54f35caSApple OSS Distributions 	enableTracing = context->enableTracing && (notifier != NULL);
6408*c54f35caSApple OSS Distributions 
6409*c54f35caSApple OSS Distributions 	IOServicePM * pwrMgt = context->us->pwrMgt;
6410*c54f35caSApple OSS Distributions 	if (gIOKitDebug & kIOLogPower) {
6411*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
6412*c54f35caSApple OSS Distributions 		if (OSDynamicCast(IOService, object)) {
6413*c54f35caSApple OSS Distributions 			const char *who = ((IOService *) object)->getName();
6414*c54f35caSApple OSS Distributions 			gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
6415*c54f35caSApple OSS Distributions 		} else if (notifier) {
6416*c54f35caSApple OSS Distributions 			OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
6417*c54f35caSApple OSS Distributions 		}
6418*c54f35caSApple OSS Distributions 	}
6419*c54f35caSApple OSS Distributions 
6420*c54f35caSApple OSS Distributions 	if (NULL == context->notifyClients) {
6421*c54f35caSApple OSS Distributions 		context->notifyClients = OSArray::withCapacity(32);
6422*c54f35caSApple OSS Distributions 		assert(context->notifyClients != NULL);
6423*c54f35caSApple OSS Distributions 	}
6424*c54f35caSApple OSS Distributions 
6425*c54f35caSApple OSS Distributions 	notify.powerRef    = (void *)(uintptr_t) msgRef;
6426*c54f35caSApple OSS Distributions 	notify.returnValue = 0;
6427*c54f35caSApple OSS Distributions 	notify.stateNumber = context->stateNumber;
6428*c54f35caSApple OSS Distributions 	notify.stateFlags  = context->stateFlags;
6429*c54f35caSApple OSS Distributions 
6430*c54f35caSApple OSS Distributions 	clock_get_uptime(&start);
6431*c54f35caSApple OSS Distributions 	if (enableTracing) {
6432*c54f35caSApple OSS Distributions 		getPMRootDomain()->traceNotification(notifier, true, start, msgIndex);
6433*c54f35caSApple OSS Distributions 	}
6434*c54f35caSApple OSS Distributions 
6435*c54f35caSApple OSS Distributions 	retCode = context->us->messageClient(msgType, object, (void *) &notify, sizeof(notify));
6436*c54f35caSApple OSS Distributions 
6437*c54f35caSApple OSS Distributions 	clock_get_uptime(&end);
6438*c54f35caSApple OSS Distributions 	if (enableTracing) {
6439*c54f35caSApple OSS Distributions 		getPMRootDomain()->traceNotification(notifier, false, end);
6440*c54f35caSApple OSS Distributions 	}
6441*c54f35caSApple OSS Distributions 
6442*c54f35caSApple OSS Distributions 	if (kIOReturnSuccess == retCode) {
6443*c54f35caSApple OSS Distributions 		if (0 == notify.returnValue) {
6444*c54f35caSApple OSS Distributions 			OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
6445*c54f35caSApple OSS Distributions 			context->responseArray->setObject(msgIndex, replied);
6446*c54f35caSApple OSS Distributions 		} else {
6447*c54f35caSApple OSS Distributions 			replied = kOSBooleanFalse;
6448*c54f35caSApple OSS Distributions 			if (notify.returnValue > context->maxTimeRequested) {
6449*c54f35caSApple OSS Distributions 				if (notify.returnValue > kPriorityClientMaxWait) {
6450*c54f35caSApple OSS Distributions 					context->maxTimeRequested = kPriorityClientMaxWait;
6451*c54f35caSApple OSS Distributions 					PM_ERROR("%s: client %p returned %llu for %s\n",
6452*c54f35caSApple OSS Distributions 					    context->us->getName(),
6453*c54f35caSApple OSS Distributions 					    notifier ? (void *)  OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6454*c54f35caSApple OSS Distributions 					    (uint64_t) notify.returnValue,
6455*c54f35caSApple OSS Distributions 					    getIOMessageString(msgType));
6456*c54f35caSApple OSS Distributions 				} else {
6457*c54f35caSApple OSS Distributions 					context->maxTimeRequested = (typeof(context->maxTimeRequested))notify.returnValue;
6458*c54f35caSApple OSS Distributions 				}
6459*c54f35caSApple OSS Distributions 			}
6460*c54f35caSApple OSS Distributions 			//
6461*c54f35caSApple OSS Distributions 			// Track time taken to ack, by storing the timestamp of
6462*c54f35caSApple OSS Distributions 			// callback completion
6463*c54f35caSApple OSS Distributions 			OSNumber * num;
6464*c54f35caSApple OSS Distributions 			num = OSNumber::withNumber(AbsoluteTime_to_scalar(&end), sizeof(uint64_t) * 8);
6465*c54f35caSApple OSS Distributions 			if (num) {
6466*c54f35caSApple OSS Distributions 				context->responseArray->setObject(msgIndex, num);
6467*c54f35caSApple OSS Distributions 				num->release();
6468*c54f35caSApple OSS Distributions 			} else {
6469*c54f35caSApple OSS Distributions 				context->responseArray->setObject(msgIndex, replied);
6470*c54f35caSApple OSS Distributions 			}
6471*c54f35caSApple OSS Distributions 		}
6472*c54f35caSApple OSS Distributions 
6473*c54f35caSApple OSS Distributions 		if (enableTracing) {
6474*c54f35caSApple OSS Distributions 			SUB_ABSOLUTETIME(&end, &start);
6475*c54f35caSApple OSS Distributions 			absolutetime_to_nanoseconds(end, &nsec);
6476*c54f35caSApple OSS Distributions 
6477*c54f35caSApple OSS Distributions 			if ((nsec > LOG_KEXT_RESPONSE_TIMES) || (notify.returnValue != 0)) {
6478*c54f35caSApple OSS Distributions 				getPMRootDomain()->traceNotificationResponse(notifier, NS_TO_MS(nsec), (uint32_t) notify.returnValue);
6479*c54f35caSApple OSS Distributions 			}
6480*c54f35caSApple OSS Distributions 		}
6481*c54f35caSApple OSS Distributions 	} else {
6482*c54f35caSApple OSS Distributions 		// not a client of ours
6483*c54f35caSApple OSS Distributions 		// so we won't be waiting for response
6484*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
6485*c54f35caSApple OSS Distributions 		context->responseArray->setObject(msgIndex, replied);
6486*c54f35caSApple OSS Distributions 	}
6487*c54f35caSApple OSS Distributions 	if (context->notifyClients) {
6488*c54f35caSApple OSS Distributions 		context->notifyClients->setObject(msgIndex, object);
6489*c54f35caSApple OSS Distributions 	}
6490*c54f35caSApple OSS Distributions }
6491*c54f35caSApple OSS Distributions 
6492*c54f35caSApple OSS Distributions //*********************************************************************************
6493*c54f35caSApple OSS Distributions // [static private] pmTellCapabilityAppWithResponse
6494*c54f35caSApple OSS Distributions //*********************************************************************************
6495*c54f35caSApple OSS Distributions 
6496*c54f35caSApple OSS Distributions void
pmTellCapabilityAppWithResponse(OSObject * object,void * arg)6497*c54f35caSApple OSS Distributions IOService::pmTellCapabilityAppWithResponse( OSObject * object, void * arg )
6498*c54f35caSApple OSS Distributions {
6499*c54f35caSApple OSS Distributions 	IOPMSystemCapabilityChangeParameters msgArg;
6500*c54f35caSApple OSS Distributions 	IOPMInterestContext *       context = (IOPMInterestContext *) arg;
6501*c54f35caSApple OSS Distributions 	OSObject *                  waitForReply = kOSBooleanFalse;
6502*c54f35caSApple OSS Distributions 	IOServicePM *               pwrMgt = context->us->pwrMgt;
6503*c54f35caSApple OSS Distributions 	uint32_t                    msgIndex, msgRef, msgType;
6504*c54f35caSApple OSS Distributions #if LOG_APP_RESPONSE_TIMES
6505*c54f35caSApple OSS Distributions 	AbsoluteTime                now;
6506*c54f35caSApple OSS Distributions #endif
6507*c54f35caSApple OSS Distributions 
6508*c54f35caSApple OSS Distributions 	if (!OSDynamicCast(_IOServiceInterestNotifier, object)) {
6509*c54f35caSApple OSS Distributions 		return;
6510*c54f35caSApple OSS Distributions 	}
6511*c54f35caSApple OSS Distributions 
6512*c54f35caSApple OSS Distributions 	memset(&msgArg, 0, sizeof(msgArg));
6513*c54f35caSApple OSS Distributions 	if (context->messageFilter &&
6514*c54f35caSApple OSS Distributions 	    !context->messageFilter(context->us, object, context, &msgArg, &waitForReply)) {
6515*c54f35caSApple OSS Distributions 		return;
6516*c54f35caSApple OSS Distributions 	}
6517*c54f35caSApple OSS Distributions 
6518*c54f35caSApple OSS Distributions 	if (context->us == getPMRootDomain() &&
6519*c54f35caSApple OSS Distributions 	    getPMRootDomain()->isAOTMode()
6520*c54f35caSApple OSS Distributions 	    ) {
6521*c54f35caSApple OSS Distributions 		OSNumber                *clientID = NULL;
6522*c54f35caSApple OSS Distributions 		boolean_t               proc_suspended = FALSE;
6523*c54f35caSApple OSS Distributions 		proc_t                proc = NULL;
6524*c54f35caSApple OSS Distributions 		if ((clientID = copyClientIDForNotification(object, context))) {
6525*c54f35caSApple OSS Distributions 			uint32_t clientPID = clientID->unsigned32BitValue();
6526*c54f35caSApple OSS Distributions 			clientID->release();
6527*c54f35caSApple OSS Distributions 			proc = proc_find(clientPID);
6528*c54f35caSApple OSS Distributions 			if (proc) {
6529*c54f35caSApple OSS Distributions 				proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6530*c54f35caSApple OSS Distributions 				if (proc_suspended) {
6531*c54f35caSApple OSS Distributions 					logClientIDForNotification(object, context, "PMTellCapablityAppWithResponse - Suspended");
6532*c54f35caSApple OSS Distributions 				} else if (get_task_suspended((task_t) proc_task(proc))) {
6533*c54f35caSApple OSS Distributions 					proc_suspended = true;
6534*c54f35caSApple OSS Distributions 					context->skippedInDark++;
6535*c54f35caSApple OSS Distributions 				}
6536*c54f35caSApple OSS Distributions 				proc_rele(proc);
6537*c54f35caSApple OSS Distributions 				if (proc_suspended) {
6538*c54f35caSApple OSS Distributions 					return;
6539*c54f35caSApple OSS Distributions 				}
6540*c54f35caSApple OSS Distributions 			}
6541*c54f35caSApple OSS Distributions 		}
6542*c54f35caSApple OSS Distributions 	}
6543*c54f35caSApple OSS Distributions 	context->notSkippedInDark++;
6544*c54f35caSApple OSS Distributions 
6545*c54f35caSApple OSS Distributions 	// Create client array (for tracking purposes) only if the service
6546*c54f35caSApple OSS Distributions 	// has app clients. Usually only root domain does.
6547*c54f35caSApple OSS Distributions 	if (NULL == context->notifyClients) {
6548*c54f35caSApple OSS Distributions 		context->notifyClients = OSArray::withCapacity(32);
6549*c54f35caSApple OSS Distributions 		assert(context->notifyClients != NULL);
6550*c54f35caSApple OSS Distributions 	}
6551*c54f35caSApple OSS Distributions 
6552*c54f35caSApple OSS Distributions 	msgType  = context->messageType;
6553*c54f35caSApple OSS Distributions 	msgIndex = context->responseArray->getCount();
6554*c54f35caSApple OSS Distributions 	msgRef   = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6555*c54f35caSApple OSS Distributions 
6556*c54f35caSApple OSS Distributions 	OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
6557*c54f35caSApple OSS Distributions 	if (kIOLogDebugPower & gIOKitDebug) {
6558*c54f35caSApple OSS Distributions 		// Log client pid/name and client array index.
6559*c54f35caSApple OSS Distributions 		OSNumber * clientID = NULL;
6560*c54f35caSApple OSS Distributions 		OSString * clientIDString = NULL;
6561*c54f35caSApple OSS Distributions 		context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
6562*c54f35caSApple OSS Distributions 		if (clientID) {
6563*c54f35caSApple OSS Distributions 			clientIDString = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6564*c54f35caSApple OSS Distributions 		}
6565*c54f35caSApple OSS Distributions 
6566*c54f35caSApple OSS Distributions 		PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
6567*c54f35caSApple OSS Distributions 		    context->us->getName(),
6568*c54f35caSApple OSS Distributions 		    msgIndex, getIOMessageString(msgType),
6569*c54f35caSApple OSS Distributions 		    (waitForReply == kOSBooleanTrue),
6570*c54f35caSApple OSS Distributions 		    clientIDString ? clientIDString->getCStringNoCopy() : "");
6571*c54f35caSApple OSS Distributions 		if (clientID) {
6572*c54f35caSApple OSS Distributions 			clientID->release();
6573*c54f35caSApple OSS Distributions 		}
6574*c54f35caSApple OSS Distributions 		if (clientIDString) {
6575*c54f35caSApple OSS Distributions 			clientIDString->release();
6576*c54f35caSApple OSS Distributions 		}
6577*c54f35caSApple OSS Distributions 	}
6578*c54f35caSApple OSS Distributions 
6579*c54f35caSApple OSS Distributions 	msgArg.notifyRef = msgRef;
6580*c54f35caSApple OSS Distributions 	msgArg.maxWaitForReply = 0;
6581*c54f35caSApple OSS Distributions 
6582*c54f35caSApple OSS Distributions 	if (waitForReply == kOSBooleanFalse) {
6583*c54f35caSApple OSS Distributions 		msgArg.notifyRef = 0;
6584*c54f35caSApple OSS Distributions 		context->responseArray->setObject(msgIndex, kOSBooleanTrue);
6585*c54f35caSApple OSS Distributions 		if (context->notifyClients) {
6586*c54f35caSApple OSS Distributions 			context->notifyClients->setObject(msgIndex, kOSBooleanTrue);
6587*c54f35caSApple OSS Distributions 		}
6588*c54f35caSApple OSS Distributions 	} else {
6589*c54f35caSApple OSS Distributions 		OSNumber * num;
6590*c54f35caSApple OSS Distributions 		clock_get_uptime(&now);
6591*c54f35caSApple OSS Distributions 		num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
6592*c54f35caSApple OSS Distributions 		if (num) {
6593*c54f35caSApple OSS Distributions 			context->responseArray->setObject(msgIndex, num);
6594*c54f35caSApple OSS Distributions 			num->release();
6595*c54f35caSApple OSS Distributions 		} else {
6596*c54f35caSApple OSS Distributions 			context->responseArray->setObject(msgIndex, kOSBooleanFalse);
6597*c54f35caSApple OSS Distributions 		}
6598*c54f35caSApple OSS Distributions 
6599*c54f35caSApple OSS Distributions 		if (context->notifyClients) {
6600*c54f35caSApple OSS Distributions 			context->notifyClients->setObject(msgIndex, object);
6601*c54f35caSApple OSS Distributions 		}
6602*c54f35caSApple OSS Distributions 	}
6603*c54f35caSApple OSS Distributions 
6604*c54f35caSApple OSS Distributions 	context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
6605*c54f35caSApple OSS Distributions }
6606*c54f35caSApple OSS Distributions 
6607*c54f35caSApple OSS Distributions //*********************************************************************************
6608*c54f35caSApple OSS Distributions // [static private] pmTellCapabilityClientWithResponse
6609*c54f35caSApple OSS Distributions //*********************************************************************************
6610*c54f35caSApple OSS Distributions 
6611*c54f35caSApple OSS Distributions void
pmTellCapabilityClientWithResponse(OSObject * object,void * arg)6612*c54f35caSApple OSS Distributions IOService::pmTellCapabilityClientWithResponse(
6613*c54f35caSApple OSS Distributions 	OSObject * object, void * arg )
6614*c54f35caSApple OSS Distributions {
6615*c54f35caSApple OSS Distributions 	IOPMSystemCapabilityChangeParameters msgArg;
6616*c54f35caSApple OSS Distributions 	IOPMInterestContext *           context = (IOPMInterestContext *) arg;
6617*c54f35caSApple OSS Distributions 	OSObject *                      replied = kOSBooleanTrue;
6618*c54f35caSApple OSS Distributions 	_IOServiceInterestNotifier *    notifier;
6619*c54f35caSApple OSS Distributions 	uint32_t                        msgIndex, msgRef, msgType;
6620*c54f35caSApple OSS Distributions 	IOReturn                        retCode;
6621*c54f35caSApple OSS Distributions 	AbsoluteTime                    start, end;
6622*c54f35caSApple OSS Distributions 	uint64_t                        nsec;
6623*c54f35caSApple OSS Distributions 	bool                            enableTracing;
6624*c54f35caSApple OSS Distributions 
6625*c54f35caSApple OSS Distributions 	memset(&msgArg, 0, sizeof(msgArg));
6626*c54f35caSApple OSS Distributions 	if (context->messageFilter &&
6627*c54f35caSApple OSS Distributions 	    !context->messageFilter(context->us, object, context, &msgArg, NULL)) {
6628*c54f35caSApple OSS Distributions 		getPMRootDomain()->traceFilteredNotification(object);
6629*c54f35caSApple OSS Distributions 		return;
6630*c54f35caSApple OSS Distributions 	}
6631*c54f35caSApple OSS Distributions 
6632*c54f35caSApple OSS Distributions 	if (NULL == context->notifyClients) {
6633*c54f35caSApple OSS Distributions 		context->notifyClients = OSArray::withCapacity(32);
6634*c54f35caSApple OSS Distributions 		assert(context->notifyClients != NULL);
6635*c54f35caSApple OSS Distributions 	}
6636*c54f35caSApple OSS Distributions 
6637*c54f35caSApple OSS Distributions 	notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
6638*c54f35caSApple OSS Distributions 	msgType  = context->messageType;
6639*c54f35caSApple OSS Distributions 	msgIndex = context->responseArray->getCount();
6640*c54f35caSApple OSS Distributions 	msgRef   = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6641*c54f35caSApple OSS Distributions 	enableTracing = context->enableTracing && (notifier != NULL);
6642*c54f35caSApple OSS Distributions 
6643*c54f35caSApple OSS Distributions 	IOServicePM * pwrMgt = context->us->pwrMgt;
6644*c54f35caSApple OSS Distributions 	if (gIOKitDebug & kIOLogPower) {
6645*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
6646*c54f35caSApple OSS Distributions 		if (OSDynamicCast(IOService, object)) {
6647*c54f35caSApple OSS Distributions 			const char *who = ((IOService *) object)->getName();
6648*c54f35caSApple OSS Distributions 			gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
6649*c54f35caSApple OSS Distributions 		} else if (notifier) {
6650*c54f35caSApple OSS Distributions 			OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
6651*c54f35caSApple OSS Distributions 		}
6652*c54f35caSApple OSS Distributions 	}
6653*c54f35caSApple OSS Distributions 
6654*c54f35caSApple OSS Distributions 	msgArg.notifyRef = msgRef;
6655*c54f35caSApple OSS Distributions 	msgArg.maxWaitForReply = 0;
6656*c54f35caSApple OSS Distributions 
6657*c54f35caSApple OSS Distributions 	clock_get_uptime(&start);
6658*c54f35caSApple OSS Distributions 	if (enableTracing) {
6659*c54f35caSApple OSS Distributions 		getPMRootDomain()->traceNotification(notifier, true, start, msgIndex);
6660*c54f35caSApple OSS Distributions 	}
6661*c54f35caSApple OSS Distributions 
6662*c54f35caSApple OSS Distributions 	retCode = context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
6663*c54f35caSApple OSS Distributions 
6664*c54f35caSApple OSS Distributions 	clock_get_uptime(&end);
6665*c54f35caSApple OSS Distributions 	if (enableTracing) {
6666*c54f35caSApple OSS Distributions 		getPMRootDomain()->traceNotification(notifier, false, end, msgIndex);
6667*c54f35caSApple OSS Distributions 	}
6668*c54f35caSApple OSS Distributions 
6669*c54f35caSApple OSS Distributions 	if (kIOReturnSuccess == retCode) {
6670*c54f35caSApple OSS Distributions 		if (0 == msgArg.maxWaitForReply) {
6671*c54f35caSApple OSS Distributions 			// client doesn't want time to respond
6672*c54f35caSApple OSS Distributions 			OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
6673*c54f35caSApple OSS Distributions 			context->responseArray->setObject(msgIndex, replied);
6674*c54f35caSApple OSS Distributions 		} else {
6675*c54f35caSApple OSS Distributions 			replied = kOSBooleanFalse;
6676*c54f35caSApple OSS Distributions 			if (msgArg.maxWaitForReply > context->maxTimeRequested) {
6677*c54f35caSApple OSS Distributions 				if (msgArg.maxWaitForReply > kCapabilityClientMaxWait) {
6678*c54f35caSApple OSS Distributions 					context->maxTimeRequested = kCapabilityClientMaxWait;
6679*c54f35caSApple OSS Distributions 					PM_ERROR("%s: client %p returned %u for %s\n",
6680*c54f35caSApple OSS Distributions 					    context->us->getName(),
6681*c54f35caSApple OSS Distributions 					    notifier ? (void *) OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6682*c54f35caSApple OSS Distributions 					    msgArg.maxWaitForReply,
6683*c54f35caSApple OSS Distributions 					    getIOMessageString(msgType));
6684*c54f35caSApple OSS Distributions 				} else {
6685*c54f35caSApple OSS Distributions 					context->maxTimeRequested = msgArg.maxWaitForReply;
6686*c54f35caSApple OSS Distributions 				}
6687*c54f35caSApple OSS Distributions 			}
6688*c54f35caSApple OSS Distributions 
6689*c54f35caSApple OSS Distributions 			// Track time taken to ack, by storing the timestamp of
6690*c54f35caSApple OSS Distributions 			// callback completion
6691*c54f35caSApple OSS Distributions 			OSNumber * num;
6692*c54f35caSApple OSS Distributions 			num = OSNumber::withNumber(AbsoluteTime_to_scalar(&end), sizeof(uint64_t) * 8);
6693*c54f35caSApple OSS Distributions 			if (num) {
6694*c54f35caSApple OSS Distributions 				context->responseArray->setObject(msgIndex, num);
6695*c54f35caSApple OSS Distributions 				num->release();
6696*c54f35caSApple OSS Distributions 			} else {
6697*c54f35caSApple OSS Distributions 				context->responseArray->setObject(msgIndex, replied);
6698*c54f35caSApple OSS Distributions 			}
6699*c54f35caSApple OSS Distributions 		}
6700*c54f35caSApple OSS Distributions 
6701*c54f35caSApple OSS Distributions 		if (enableTracing) {
6702*c54f35caSApple OSS Distributions 			SUB_ABSOLUTETIME(&end, &start);
6703*c54f35caSApple OSS Distributions 			absolutetime_to_nanoseconds(end, &nsec);
6704*c54f35caSApple OSS Distributions 
6705*c54f35caSApple OSS Distributions 			if ((nsec > LOG_KEXT_RESPONSE_TIMES) || (msgArg.maxWaitForReply != 0)) {
6706*c54f35caSApple OSS Distributions 				getPMRootDomain()->traceNotificationResponse(notifier, NS_TO_MS(nsec), msgArg.maxWaitForReply);
6707*c54f35caSApple OSS Distributions 			}
6708*c54f35caSApple OSS Distributions 		}
6709*c54f35caSApple OSS Distributions 	} else {
6710*c54f35caSApple OSS Distributions 		// not a client of ours
6711*c54f35caSApple OSS Distributions 		// so we won't be waiting for response
6712*c54f35caSApple OSS Distributions 		OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
6713*c54f35caSApple OSS Distributions 		context->responseArray->setObject(msgIndex, replied);
6714*c54f35caSApple OSS Distributions 	}
6715*c54f35caSApple OSS Distributions 	if (context->notifyClients) {
6716*c54f35caSApple OSS Distributions 		context->notifyClients->setObject(msgIndex, object);
6717*c54f35caSApple OSS Distributions 	}
6718*c54f35caSApple OSS Distributions }
6719*c54f35caSApple OSS Distributions 
6720*c54f35caSApple OSS Distributions //*********************************************************************************
6721*c54f35caSApple OSS Distributions // [public] tellNoChangeDown
6722*c54f35caSApple OSS Distributions //
6723*c54f35caSApple OSS Distributions // Notify registered applications and kernel clients that we are not
6724*c54f35caSApple OSS Distributions // dropping power.
6725*c54f35caSApple OSS Distributions //
6726*c54f35caSApple OSS Distributions // Subclass can override this to send a different message type.  Parameter is
6727*c54f35caSApple OSS Distributions // the aborted destination state number.
6728*c54f35caSApple OSS Distributions //*********************************************************************************
6729*c54f35caSApple OSS Distributions 
6730*c54f35caSApple OSS Distributions void
tellNoChangeDown(unsigned long)6731*c54f35caSApple OSS Distributions IOService::tellNoChangeDown( unsigned long )
6732*c54f35caSApple OSS Distributions {
6733*c54f35caSApple OSS Distributions 	return tellClients( kIOMessageDeviceWillNotPowerOff );
6734*c54f35caSApple OSS Distributions }
6735*c54f35caSApple OSS Distributions 
6736*c54f35caSApple OSS Distributions //*********************************************************************************
6737*c54f35caSApple OSS Distributions // [public] tellChangeUp
6738*c54f35caSApple OSS Distributions //
6739*c54f35caSApple OSS Distributions // Notify registered applications and kernel clients that we are raising power.
6740*c54f35caSApple OSS Distributions //
6741*c54f35caSApple OSS Distributions // Subclass can override this to send a different message type.  Parameter is
6742*c54f35caSApple OSS Distributions // the aborted destination state number.
6743*c54f35caSApple OSS Distributions //*********************************************************************************
6744*c54f35caSApple OSS Distributions 
6745*c54f35caSApple OSS Distributions void
tellChangeUp(unsigned long)6746*c54f35caSApple OSS Distributions IOService::tellChangeUp( unsigned long )
6747*c54f35caSApple OSS Distributions {
6748*c54f35caSApple OSS Distributions 	return tellClients( kIOMessageDeviceHasPoweredOn );
6749*c54f35caSApple OSS Distributions }
6750*c54f35caSApple OSS Distributions 
6751*c54f35caSApple OSS Distributions //*********************************************************************************
6752*c54f35caSApple OSS Distributions // [protected] tellClients
6753*c54f35caSApple OSS Distributions //
6754*c54f35caSApple OSS Distributions // Notify registered applications and kernel clients of something.
6755*c54f35caSApple OSS Distributions //*********************************************************************************
6756*c54f35caSApple OSS Distributions 
6757*c54f35caSApple OSS Distributions void
tellClients(int messageType)6758*c54f35caSApple OSS Distributions IOService::tellClients( int messageType )
6759*c54f35caSApple OSS Distributions {
6760*c54f35caSApple OSS Distributions 	IOPMInterestContext     context;
6761*c54f35caSApple OSS Distributions 
6762*c54f35caSApple OSS Distributions 	RD_LOG("tellClients( %s )\n", getIOMessageString(messageType));
6763*c54f35caSApple OSS Distributions 
6764*c54f35caSApple OSS Distributions 	memset(&context, 0, sizeof(context));
6765*c54f35caSApple OSS Distributions 	context.messageType   = messageType;
6766*c54f35caSApple OSS Distributions 	context.isPreChange   = fIsPreChange;
6767*c54f35caSApple OSS Distributions 	context.us            = this;
6768*c54f35caSApple OSS Distributions 	context.stateNumber   = fHeadNotePowerState;
6769*c54f35caSApple OSS Distributions 	context.stateFlags    = fHeadNotePowerArrayEntry->capabilityFlags;
6770*c54f35caSApple OSS Distributions 	context.changeFlags   = fHeadNoteChangeFlags;
6771*c54f35caSApple OSS Distributions 	context.enableTracing = IS_ROOT_DOMAIN;
6772*c54f35caSApple OSS Distributions 	context.messageFilter = (IS_ROOT_DOMAIN) ?
6773*c54f35caSApple OSS Distributions 	    OSMemberFunctionCast(
6774*c54f35caSApple OSS Distributions 		IOPMMessageFilter,
6775*c54f35caSApple OSS Distributions 		(IOPMrootDomain *)this,
6776*c54f35caSApple OSS Distributions 		&IOPMrootDomain::systemMessageFilter) : NULL;
6777*c54f35caSApple OSS Distributions 
6778*c54f35caSApple OSS Distributions 	context.notifyType = kNotifyPriority;
6779*c54f35caSApple OSS Distributions 	applyToInterested( gIOPriorityPowerStateInterest,
6780*c54f35caSApple OSS Distributions 	    tellKernelClientApplier, (void *) &context );
6781*c54f35caSApple OSS Distributions 
6782*c54f35caSApple OSS Distributions 	context.notifyType = kNotifyApps;
6783*c54f35caSApple OSS Distributions 	applyToInterested( gIOAppPowerStateInterest,
6784*c54f35caSApple OSS Distributions 	    tellAppClientApplier, (void *) &context );
6785*c54f35caSApple OSS Distributions 
6786*c54f35caSApple OSS Distributions 	applyToInterested( gIOGeneralInterest,
6787*c54f35caSApple OSS Distributions 	    tellKernelClientApplier, (void *) &context );
6788*c54f35caSApple OSS Distributions }
6789*c54f35caSApple OSS Distributions 
6790*c54f35caSApple OSS Distributions //*********************************************************************************
6791*c54f35caSApple OSS Distributions // [private] tellKernelClientApplier
6792*c54f35caSApple OSS Distributions //
6793*c54f35caSApple OSS Distributions // Message a kernel client.
6794*c54f35caSApple OSS Distributions //*********************************************************************************
6795*c54f35caSApple OSS Distributions 
6796*c54f35caSApple OSS Distributions static void
tellKernelClientApplier(OSObject * object,void * arg)6797*c54f35caSApple OSS Distributions tellKernelClientApplier( OSObject * object, void * arg )
6798*c54f35caSApple OSS Distributions {
6799*c54f35caSApple OSS Distributions 	IOPowerStateChangeNotification  notify;
6800*c54f35caSApple OSS Distributions 	IOPMInterestContext *           context = (IOPMInterestContext *) arg;
6801*c54f35caSApple OSS Distributions 	bool                            enableTracing = context->enableTracing;
6802*c54f35caSApple OSS Distributions 
6803*c54f35caSApple OSS Distributions 	if (context->messageFilter &&
6804*c54f35caSApple OSS Distributions 	    !context->messageFilter(context->us, object, context, NULL, NULL)) {
6805*c54f35caSApple OSS Distributions 		IOService::getPMRootDomain()->traceFilteredNotification(object);
6806*c54f35caSApple OSS Distributions 		return;
6807*c54f35caSApple OSS Distributions 	}
6808*c54f35caSApple OSS Distributions 
6809*c54f35caSApple OSS Distributions 	notify.powerRef     = (void *) NULL;
6810*c54f35caSApple OSS Distributions 	notify.returnValue  = 0;
6811*c54f35caSApple OSS Distributions 	notify.stateNumber  = context->stateNumber;
6812*c54f35caSApple OSS Distributions 	notify.stateFlags   = context->stateFlags;
6813*c54f35caSApple OSS Distributions 
6814*c54f35caSApple OSS Distributions 	if (enableTracing) {
6815*c54f35caSApple OSS Distributions 		IOService::getPMRootDomain()->traceNotification(object, true);
6816*c54f35caSApple OSS Distributions 	}
6817*c54f35caSApple OSS Distributions 
6818*c54f35caSApple OSS Distributions 	context->us->messageClient(context->messageType, object, &notify, sizeof(notify));
6819*c54f35caSApple OSS Distributions 
6820*c54f35caSApple OSS Distributions 	if (enableTracing) {
6821*c54f35caSApple OSS Distributions 		IOService::getPMRootDomain()->traceNotification(object, false);
6822*c54f35caSApple OSS Distributions 	}
6823*c54f35caSApple OSS Distributions }
6824*c54f35caSApple OSS Distributions 
6825*c54f35caSApple OSS Distributions static OSNumber *
copyClientIDForNotification(OSObject * object,IOPMInterestContext * context)6826*c54f35caSApple OSS Distributions copyClientIDForNotification(
6827*c54f35caSApple OSS Distributions 	OSObject *object,
6828*c54f35caSApple OSS Distributions 	IOPMInterestContext *context)
6829*c54f35caSApple OSS Distributions {
6830*c54f35caSApple OSS Distributions 	OSNumber *clientID = NULL;
6831*c54f35caSApple OSS Distributions 	context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
6832*c54f35caSApple OSS Distributions 	return clientID;
6833*c54f35caSApple OSS Distributions }
6834*c54f35caSApple OSS Distributions 
6835*c54f35caSApple OSS Distributions static void
logClientIDForNotification(OSObject * object,IOPMInterestContext * context,const char * logString)6836*c54f35caSApple OSS Distributions logClientIDForNotification(
6837*c54f35caSApple OSS Distributions 	OSObject *object,
6838*c54f35caSApple OSS Distributions 	IOPMInterestContext *context,
6839*c54f35caSApple OSS Distributions 	const char *logString)
6840*c54f35caSApple OSS Distributions {
6841*c54f35caSApple OSS Distributions 	OSString *logClientID = NULL;
6842*c54f35caSApple OSS Distributions 	OSNumber *clientID = copyClientIDForNotification(object, context);
6843*c54f35caSApple OSS Distributions 
6844*c54f35caSApple OSS Distributions 	if (logString) {
6845*c54f35caSApple OSS Distributions 		if (clientID) {
6846*c54f35caSApple OSS Distributions 			logClientID = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6847*c54f35caSApple OSS Distributions 		}
6848*c54f35caSApple OSS Distributions 
6849*c54f35caSApple OSS Distributions 		PM_LOG("%s %s %s, %s\n",
6850*c54f35caSApple OSS Distributions 		    context->us->getName(), logString,
6851*c54f35caSApple OSS Distributions 		    IOService::getIOMessageString(context->messageType),
6852*c54f35caSApple OSS Distributions 		    logClientID ? logClientID->getCStringNoCopy() : "");
6853*c54f35caSApple OSS Distributions 
6854*c54f35caSApple OSS Distributions 		if (logClientID) {
6855*c54f35caSApple OSS Distributions 			logClientID->release();
6856*c54f35caSApple OSS Distributions 		}
6857*c54f35caSApple OSS Distributions 	}
6858*c54f35caSApple OSS Distributions 
6859*c54f35caSApple OSS Distributions 	if (clientID) {
6860*c54f35caSApple OSS Distributions 		clientID->release();
6861*c54f35caSApple OSS Distributions 	}
6862*c54f35caSApple OSS Distributions 
6863*c54f35caSApple OSS Distributions 	return;
6864*c54f35caSApple OSS Distributions }
6865*c54f35caSApple OSS Distributions 
6866*c54f35caSApple OSS Distributions static void
tellAppClientApplier(OSObject * object,void * arg)6867*c54f35caSApple OSS Distributions tellAppClientApplier( OSObject * object, void * arg )
6868*c54f35caSApple OSS Distributions {
6869*c54f35caSApple OSS Distributions 	IOPMInterestContext * context = (IOPMInterestContext *) arg;
6870*c54f35caSApple OSS Distributions 	OSNumber            * clientID = NULL;
6871*c54f35caSApple OSS Distributions 	proc_t                proc = NULL;
6872*c54f35caSApple OSS Distributions 	boolean_t             proc_suspended = FALSE;
6873*c54f35caSApple OSS Distributions 
6874*c54f35caSApple OSS Distributions 	if (context->us == IOService::getPMRootDomain()) {
6875*c54f35caSApple OSS Distributions 		if ((clientID = copyClientIDForNotification(object, context))) {
6876*c54f35caSApple OSS Distributions 			uint32_t clientPID = clientID->unsigned32BitValue();
6877*c54f35caSApple OSS Distributions 			clientID->release();
6878*c54f35caSApple OSS Distributions 			proc = proc_find(clientPID);
6879*c54f35caSApple OSS Distributions 
6880*c54f35caSApple OSS Distributions 			if (proc) {
6881*c54f35caSApple OSS Distributions 				proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6882*c54f35caSApple OSS Distributions 				if (proc_suspended) {
6883*c54f35caSApple OSS Distributions 					logClientIDForNotification(object, context, "tellAppClientApplier - Suspended");
6884*c54f35caSApple OSS Distributions 				} else if (IOService::getPMRootDomain()->isAOTMode() && get_task_suspended((task_t) proc_task(proc))) {
6885*c54f35caSApple OSS Distributions 					proc_suspended = true;
6886*c54f35caSApple OSS Distributions 					context->skippedInDark++;
6887*c54f35caSApple OSS Distributions 				}
6888*c54f35caSApple OSS Distributions 				proc_rele(proc);
6889*c54f35caSApple OSS Distributions 				if (proc_suspended) {
6890*c54f35caSApple OSS Distributions 					return;
6891*c54f35caSApple OSS Distributions 				}
6892*c54f35caSApple OSS Distributions 			}
6893*c54f35caSApple OSS Distributions 		}
6894*c54f35caSApple OSS Distributions 	}
6895*c54f35caSApple OSS Distributions 
6896*c54f35caSApple OSS Distributions 	if (context->messageFilter &&
6897*c54f35caSApple OSS Distributions 	    !context->messageFilter(context->us, object, context, NULL, NULL)) {
6898*c54f35caSApple OSS Distributions 		if (kIOLogDebugPower & gIOKitDebug) {
6899*c54f35caSApple OSS Distributions 			logClientIDForNotification(object, context, "DROP App");
6900*c54f35caSApple OSS Distributions 		}
6901*c54f35caSApple OSS Distributions 		return;
6902*c54f35caSApple OSS Distributions 	}
6903*c54f35caSApple OSS Distributions 	context->notSkippedInDark++;
6904*c54f35caSApple OSS Distributions 
6905*c54f35caSApple OSS Distributions 	if (kIOLogDebugPower & gIOKitDebug) {
6906*c54f35caSApple OSS Distributions 		logClientIDForNotification(object, context, "MESG App");
6907*c54f35caSApple OSS Distributions 	}
6908*c54f35caSApple OSS Distributions 
6909*c54f35caSApple OSS Distributions 	context->us->messageClient(context->messageType, object, NULL);
6910*c54f35caSApple OSS Distributions }
6911*c54f35caSApple OSS Distributions 
6912*c54f35caSApple OSS Distributions //*********************************************************************************
6913*c54f35caSApple OSS Distributions // [private] checkForDone
6914*c54f35caSApple OSS Distributions //*********************************************************************************
6915*c54f35caSApple OSS Distributions 
6916*c54f35caSApple OSS Distributions bool
checkForDone(void)6917*c54f35caSApple OSS Distributions IOService::checkForDone( void )
6918*c54f35caSApple OSS Distributions {
6919*c54f35caSApple OSS Distributions 	int         i = 0;
6920*c54f35caSApple OSS Distributions 	OSObject *  theFlag;
6921*c54f35caSApple OSS Distributions 
6922*c54f35caSApple OSS Distributions 	if (fResponseArray == NULL) {
6923*c54f35caSApple OSS Distributions 		return true;
6924*c54f35caSApple OSS Distributions 	}
6925*c54f35caSApple OSS Distributions 
6926*c54f35caSApple OSS Distributions 	for (i = 0;; i++) {
6927*c54f35caSApple OSS Distributions 		theFlag = fResponseArray->getObject(i);
6928*c54f35caSApple OSS Distributions 
6929*c54f35caSApple OSS Distributions 		if (NULL == theFlag) {
6930*c54f35caSApple OSS Distributions 			break;
6931*c54f35caSApple OSS Distributions 		}
6932*c54f35caSApple OSS Distributions 
6933*c54f35caSApple OSS Distributions 		if (kOSBooleanTrue != theFlag) {
6934*c54f35caSApple OSS Distributions 			return false;
6935*c54f35caSApple OSS Distributions 		}
6936*c54f35caSApple OSS Distributions 	}
6937*c54f35caSApple OSS Distributions 	return true;
6938*c54f35caSApple OSS Distributions }
6939*c54f35caSApple OSS Distributions 
6940*c54f35caSApple OSS Distributions //*********************************************************************************
6941*c54f35caSApple OSS Distributions // [public] responseValid
6942*c54f35caSApple OSS Distributions //*********************************************************************************
6943*c54f35caSApple OSS Distributions 
6944*c54f35caSApple OSS Distributions bool
responseValid(uint32_t refcon,int pid)6945*c54f35caSApple OSS Distributions IOService::responseValid( uint32_t refcon, int pid )
6946*c54f35caSApple OSS Distributions {
6947*c54f35caSApple OSS Distributions 	UInt16          serialComponent;
6948*c54f35caSApple OSS Distributions 	UInt16          ordinalComponent;
6949*c54f35caSApple OSS Distributions 	OSObject *      theFlag;
6950*c54f35caSApple OSS Distributions 	OSObject        *object = NULL;
6951*c54f35caSApple OSS Distributions 
6952*c54f35caSApple OSS Distributions 	serialComponent  = (refcon >> 16) & 0xFFFF;
6953*c54f35caSApple OSS Distributions 	ordinalComponent = (refcon & 0xFFFF);
6954*c54f35caSApple OSS Distributions 
6955*c54f35caSApple OSS Distributions 	if (serialComponent != fSerialNumber) {
6956*c54f35caSApple OSS Distributions 		return false;
6957*c54f35caSApple OSS Distributions 	}
6958*c54f35caSApple OSS Distributions 
6959*c54f35caSApple OSS Distributions 	if (fResponseArray == NULL) {
6960*c54f35caSApple OSS Distributions 		return false;
6961*c54f35caSApple OSS Distributions 	}
6962*c54f35caSApple OSS Distributions 
6963*c54f35caSApple OSS Distributions 	theFlag = fResponseArray->getObject(ordinalComponent);
6964*c54f35caSApple OSS Distributions 
6965*c54f35caSApple OSS Distributions 	if (theFlag == NULL) {
6966*c54f35caSApple OSS Distributions 		return false;
6967*c54f35caSApple OSS Distributions 	}
6968*c54f35caSApple OSS Distributions 
6969*c54f35caSApple OSS Distributions 	if (fNotifyClientArray) {
6970*c54f35caSApple OSS Distributions 		object = fNotifyClientArray->getObject(ordinalComponent);
6971*c54f35caSApple OSS Distributions 	}
6972*c54f35caSApple OSS Distributions 
6973*c54f35caSApple OSS Distributions 	OSNumber * num;
6974*c54f35caSApple OSS Distributions 	if ((num = OSDynamicCast(OSNumber, theFlag))) {
6975*c54f35caSApple OSS Distributions 		AbsoluteTime    now;
6976*c54f35caSApple OSS Distributions 		AbsoluteTime    start;
6977*c54f35caSApple OSS Distributions 		uint64_t        nsec;
6978*c54f35caSApple OSS Distributions 		char            name[128];
6979*c54f35caSApple OSS Distributions 
6980*c54f35caSApple OSS Distributions 		clock_get_uptime(&now);
6981*c54f35caSApple OSS Distributions 		AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
6982*c54f35caSApple OSS Distributions 		SUB_ABSOLUTETIME(&now, &start);
6983*c54f35caSApple OSS Distributions 		absolutetime_to_nanoseconds(now, &nsec);
6984*c54f35caSApple OSS Distributions 
6985*c54f35caSApple OSS Distributions 		if (pid != 0) {
6986*c54f35caSApple OSS Distributions 			name[0] = '\0';
6987*c54f35caSApple OSS Distributions 			proc_name(pid, name, sizeof(name));
6988*c54f35caSApple OSS Distributions 
6989*c54f35caSApple OSS Distributions 			if (nsec > LOG_APP_RESPONSE_TIMES) {
6990*c54f35caSApple OSS Distributions 				IOLog("PM response took %d ms (%d, %s)\n", NS_TO_MS(nsec),
6991*c54f35caSApple OSS Distributions 				    pid, name);
6992*c54f35caSApple OSS Distributions 			}
6993*c54f35caSApple OSS Distributions 
6994*c54f35caSApple OSS Distributions 			if (nsec > LOG_APP_RESPONSE_MSG_TRACER) {
6995*c54f35caSApple OSS Distributions 				// TODO: populate the messageType argument
6996*c54f35caSApple OSS Distributions 				getPMRootDomain()->pmStatsRecordApplicationResponse(
6997*c54f35caSApple OSS Distributions 					gIOPMStatsResponseSlow,
6998*c54f35caSApple OSS Distributions 					name, 0, NS_TO_MS(nsec), pid, object);
6999*c54f35caSApple OSS Distributions 			} else {
7000*c54f35caSApple OSS Distributions 				getPMRootDomain()->pmStatsRecordApplicationResponse(
7001*c54f35caSApple OSS Distributions 					gIOPMStatsResponsePrompt,
7002*c54f35caSApple OSS Distributions 					name, 0, NS_TO_MS(nsec), pid, object);
7003*c54f35caSApple OSS Distributions 			}
7004*c54f35caSApple OSS Distributions 		} else {
7005*c54f35caSApple OSS Distributions 			getPMRootDomain()->traceNotificationAck(object, NS_TO_MS(nsec));
7006*c54f35caSApple OSS Distributions 		}
7007*c54f35caSApple OSS Distributions 
7008*c54f35caSApple OSS Distributions 		if (kIOLogDebugPower & gIOKitDebug) {
7009*c54f35caSApple OSS Distributions 			PM_LOG("Ack(%u) %u ms\n",
7010*c54f35caSApple OSS Distributions 			    (uint32_t) ordinalComponent,
7011*c54f35caSApple OSS Distributions 			    NS_TO_MS(nsec));
7012*c54f35caSApple OSS Distributions 		}
7013*c54f35caSApple OSS Distributions 		theFlag = kOSBooleanFalse;
7014*c54f35caSApple OSS Distributions 	} else if (object) {
7015*c54f35caSApple OSS Distributions 		getPMRootDomain()->pmStatsRecordApplicationResponse(
7016*c54f35caSApple OSS Distributions 			gIOPMStatsResponsePrompt,
7017*c54f35caSApple OSS Distributions 			NULL, 0, 0, pid, object);
7018*c54f35caSApple OSS Distributions 	}
7019*c54f35caSApple OSS Distributions 
7020*c54f35caSApple OSS Distributions 	if (kOSBooleanFalse == theFlag) {
7021*c54f35caSApple OSS Distributions 		fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
7022*c54f35caSApple OSS Distributions 	}
7023*c54f35caSApple OSS Distributions 
7024*c54f35caSApple OSS Distributions 	return true;
7025*c54f35caSApple OSS Distributions }
7026*c54f35caSApple OSS Distributions 
7027*c54f35caSApple OSS Distributions //*********************************************************************************
7028*c54f35caSApple OSS Distributions // [public] allowPowerChange
7029*c54f35caSApple OSS Distributions //
7030*c54f35caSApple OSS Distributions // Our power state is about to lower, and we have notified applications
7031*c54f35caSApple OSS Distributions // and kernel clients, and one of them has acknowledged.  If this is the last to do
7032*c54f35caSApple OSS Distributions // so, and all acknowledgements are positive, we continue with the power change.
7033*c54f35caSApple OSS Distributions //*********************************************************************************
7034*c54f35caSApple OSS Distributions 
7035*c54f35caSApple OSS Distributions IOReturn
allowPowerChange(unsigned long refcon)7036*c54f35caSApple OSS Distributions IOService::allowPowerChange( unsigned long refcon )
7037*c54f35caSApple OSS Distributions {
7038*c54f35caSApple OSS Distributions 	IOPMRequest * request;
7039*c54f35caSApple OSS Distributions 
7040*c54f35caSApple OSS Distributions 	if (!initialized) {
7041*c54f35caSApple OSS Distributions 		// we're unloading
7042*c54f35caSApple OSS Distributions 		return kIOReturnSuccess;
7043*c54f35caSApple OSS Distributions 	}
7044*c54f35caSApple OSS Distributions 
7045*c54f35caSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
7046*c54f35caSApple OSS Distributions 	if (!request) {
7047*c54f35caSApple OSS Distributions 		return kIOReturnNoMemory;
7048*c54f35caSApple OSS Distributions 	}
7049*c54f35caSApple OSS Distributions 
7050*c54f35caSApple OSS Distributions 	request->fArg0 = (void *)            refcon;
7051*c54f35caSApple OSS Distributions 	request->fArg1 = (void *)(uintptr_t) proc_selfpid();
7052*c54f35caSApple OSS Distributions 	request->fArg2 = (void *)            NULL;
7053*c54f35caSApple OSS Distributions 	submitPMRequest( request );
7054*c54f35caSApple OSS Distributions 
7055*c54f35caSApple OSS Distributions 	return kIOReturnSuccess;
7056*c54f35caSApple OSS Distributions }
7057*c54f35caSApple OSS Distributions 
7058*c54f35caSApple OSS Distributions #ifndef __LP64__
7059*c54f35caSApple OSS Distributions IOReturn
serializedAllowPowerChange2(unsigned long refcon)7060*c54f35caSApple OSS Distributions IOService::serializedAllowPowerChange2( unsigned long refcon )
7061*c54f35caSApple OSS Distributions {
7062*c54f35caSApple OSS Distributions 	// [deprecated] public
7063*c54f35caSApple OSS Distributions 	return kIOReturnUnsupported;
7064*c54f35caSApple OSS Distributions }
7065*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
7066*c54f35caSApple OSS Distributions 
7067*c54f35caSApple OSS Distributions //*********************************************************************************
7068*c54f35caSApple OSS Distributions // [public] cancelPowerChange
7069*c54f35caSApple OSS Distributions //
7070*c54f35caSApple OSS Distributions // Our power state is about to lower, and we have notified applications
7071*c54f35caSApple OSS Distributions // and kernel clients, and one of them has vetoed the change.  If this is the last
7072*c54f35caSApple OSS Distributions // client to respond, we abandon the power change.
7073*c54f35caSApple OSS Distributions //*********************************************************************************
7074*c54f35caSApple OSS Distributions 
7075*c54f35caSApple OSS Distributions IOReturn
cancelPowerChange(unsigned long refcon)7076*c54f35caSApple OSS Distributions IOService::cancelPowerChange( unsigned long refcon )
7077*c54f35caSApple OSS Distributions {
7078*c54f35caSApple OSS Distributions 	IOPMRequest *   request;
7079*c54f35caSApple OSS Distributions 	char            name[128];
7080*c54f35caSApple OSS Distributions 	pid_t           pid = proc_selfpid();
7081*c54f35caSApple OSS Distributions 
7082*c54f35caSApple OSS Distributions 	if (!initialized) {
7083*c54f35caSApple OSS Distributions 		// we're unloading
7084*c54f35caSApple OSS Distributions 		return kIOReturnSuccess;
7085*c54f35caSApple OSS Distributions 	}
7086*c54f35caSApple OSS Distributions 
7087*c54f35caSApple OSS Distributions 	name[0] = '\0';
7088*c54f35caSApple OSS Distributions 	proc_name(pid, name, sizeof(name));
7089*c54f35caSApple OSS Distributions 	PM_ERROR("PM notification cancel (pid %d, %s)\n", pid, name);
7090*c54f35caSApple OSS Distributions 
7091*c54f35caSApple OSS Distributions 	request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
7092*c54f35caSApple OSS Distributions 	if (!request) {
7093*c54f35caSApple OSS Distributions 		return kIOReturnNoMemory;
7094*c54f35caSApple OSS Distributions 	}
7095*c54f35caSApple OSS Distributions 
7096*c54f35caSApple OSS Distributions 	request->fArg0 = (void *)            refcon;
7097*c54f35caSApple OSS Distributions 	request->fArg1 = (void *)(uintptr_t) proc_selfpid();
7098*c54f35caSApple OSS Distributions 	request->fArg2 = (void *)            OSString::withCString(name);
7099*c54f35caSApple OSS Distributions 	submitPMRequest( request );
7100*c54f35caSApple OSS Distributions 
7101*c54f35caSApple OSS Distributions 	return kIOReturnSuccess;
7102*c54f35caSApple OSS Distributions }
7103*c54f35caSApple OSS Distributions 
7104*c54f35caSApple OSS Distributions //*********************************************************************************
7105*c54f35caSApple OSS Distributions // cancelIdlePowerDown
7106*c54f35caSApple OSS Distributions //
7107*c54f35caSApple OSS Distributions // Internal method to trigger an idle cancel or revert
7108*c54f35caSApple OSS Distributions //*********************************************************************************
7109*c54f35caSApple OSS Distributions 
7110*c54f35caSApple OSS Distributions void
cancelIdlePowerDown(IOService * service)7111*c54f35caSApple OSS Distributions IOService::cancelIdlePowerDown( IOService * service )
7112*c54f35caSApple OSS Distributions {
7113*c54f35caSApple OSS Distributions 	IOPMRequest * request;
7114*c54f35caSApple OSS Distributions 
7115*c54f35caSApple OSS Distributions 	request = acquirePMRequest(service, kIOPMRequestTypeIdleCancel);
7116*c54f35caSApple OSS Distributions 	if (request) {
7117*c54f35caSApple OSS Distributions 		submitPMRequest(request);
7118*c54f35caSApple OSS Distributions 	}
7119*c54f35caSApple OSS Distributions }
7120*c54f35caSApple OSS Distributions 
7121*c54f35caSApple OSS Distributions #ifndef __LP64__
7122*c54f35caSApple OSS Distributions IOReturn
serializedCancelPowerChange2(unsigned long refcon)7123*c54f35caSApple OSS Distributions IOService::serializedCancelPowerChange2( unsigned long refcon )
7124*c54f35caSApple OSS Distributions {
7125*c54f35caSApple OSS Distributions 	// [deprecated] public
7126*c54f35caSApple OSS Distributions 	return kIOReturnUnsupported;
7127*c54f35caSApple OSS Distributions }
7128*c54f35caSApple OSS Distributions 
7129*c54f35caSApple OSS Distributions //*********************************************************************************
7130*c54f35caSApple OSS Distributions // PM_Clamp_Timer_Expired
7131*c54f35caSApple OSS Distributions //
7132*c54f35caSApple OSS Distributions // called when clamp timer expires...set power state to 0.
7133*c54f35caSApple OSS Distributions //*********************************************************************************
7134*c54f35caSApple OSS Distributions 
7135*c54f35caSApple OSS Distributions void
PM_Clamp_Timer_Expired(void)7136*c54f35caSApple OSS Distributions IOService::PM_Clamp_Timer_Expired( void )
7137*c54f35caSApple OSS Distributions {
7138*c54f35caSApple OSS Distributions }
7139*c54f35caSApple OSS Distributions 
7140*c54f35caSApple OSS Distributions //*********************************************************************************
7141*c54f35caSApple OSS Distributions // clampPowerOn
7142*c54f35caSApple OSS Distributions //
7143*c54f35caSApple OSS Distributions // Set to highest available power state for a minimum of duration milliseconds
7144*c54f35caSApple OSS Distributions //*********************************************************************************
7145*c54f35caSApple OSS Distributions 
7146*c54f35caSApple OSS Distributions void
clampPowerOn(unsigned long duration)7147*c54f35caSApple OSS Distributions IOService::clampPowerOn( unsigned long duration )
7148*c54f35caSApple OSS Distributions {
7149*c54f35caSApple OSS Distributions }
7150*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
7151*c54f35caSApple OSS Distributions 
7152*c54f35caSApple OSS Distributions //*********************************************************************************
7153*c54f35caSApple OSS Distributions //  configurePowerStateReport
7154*c54f35caSApple OSS Distributions //
7155*c54f35caSApple OSS Distributions //  Configures the IOStateReport for kPMPowerStateChannel
7156*c54f35caSApple OSS Distributions //*********************************************************************************
7157*c54f35caSApple OSS Distributions IOReturn
configurePowerStatesReport(IOReportConfigureAction action,void * result)7158*c54f35caSApple OSS Distributions IOService::configurePowerStatesReport( IOReportConfigureAction action, void *result )
7159*c54f35caSApple OSS Distributions {
7160*c54f35caSApple OSS Distributions 	IOReturn rc = kIOReturnSuccess;
7161*c54f35caSApple OSS Distributions 	size_t  reportSize;
7162*c54f35caSApple OSS Distributions 	unsigned long i;
7163*c54f35caSApple OSS Distributions 	uint64_t ts;
7164*c54f35caSApple OSS Distributions 
7165*c54f35caSApple OSS Distributions 	if (!pwrMgt) {
7166*c54f35caSApple OSS Distributions 		return kIOReturnUnsupported;
7167*c54f35caSApple OSS Distributions 	}
7168*c54f35caSApple OSS Distributions 
7169*c54f35caSApple OSS Distributions 	if (!fNumberOfPowerStates) {
7170*c54f35caSApple OSS Distributions 		return kIOReturnSuccess; // For drivers which are in power plane, but haven't called registerPowerDriver()
7171*c54f35caSApple OSS Distributions 	}
7172*c54f35caSApple OSS Distributions 
7173*c54f35caSApple OSS Distributions 	if (fNumberOfPowerStates > INT16_MAX) {
7174*c54f35caSApple OSS Distributions 		return kIOReturnOverrun;
7175*c54f35caSApple OSS Distributions 	}
7176*c54f35caSApple OSS Distributions 	PM_LOCK();
7177*c54f35caSApple OSS Distributions 
7178*c54f35caSApple OSS Distributions 	switch (action) {
7179*c54f35caSApple OSS Distributions 	case kIOReportEnable:
7180*c54f35caSApple OSS Distributions 		if (fReportBuf) {
7181*c54f35caSApple OSS Distributions 			fReportClientCnt++;
7182*c54f35caSApple OSS Distributions 			break;
7183*c54f35caSApple OSS Distributions 		}
7184*c54f35caSApple OSS Distributions 		reportSize = STATEREPORT_BUFSIZE(fNumberOfPowerStates);
7185*c54f35caSApple OSS Distributions 		fReportBuf = IOMallocZeroData(reportSize);
7186*c54f35caSApple OSS Distributions 		if (!fReportBuf) {
7187*c54f35caSApple OSS Distributions 			rc = kIOReturnNoMemory;
7188*c54f35caSApple OSS Distributions 			break;
7189*c54f35caSApple OSS Distributions 		}
7190*c54f35caSApple OSS Distributions 
7191*c54f35caSApple OSS Distributions 		STATEREPORT_INIT((uint16_t) fNumberOfPowerStates, fReportBuf, reportSize,
7192*c54f35caSApple OSS Distributions 		    getRegistryEntryID(), kPMPowerStatesChID, kIOReportCategoryPower);
7193*c54f35caSApple OSS Distributions 
7194*c54f35caSApple OSS Distributions 		for (i = 0; i < fNumberOfPowerStates; i++) {
7195*c54f35caSApple OSS Distributions 			unsigned bits = 0;
7196*c54f35caSApple OSS Distributions 
7197*c54f35caSApple OSS Distributions 			if (fPowerStates[i].capabilityFlags & kIOPMPowerOn) {
7198*c54f35caSApple OSS Distributions 				bits |= kPMReportPowerOn;
7199*c54f35caSApple OSS Distributions 			}
7200*c54f35caSApple OSS Distributions 			if (fPowerStates[i].capabilityFlags & kIOPMDeviceUsable) {
7201*c54f35caSApple OSS Distributions 				bits |= kPMReportDeviceUsable;
7202*c54f35caSApple OSS Distributions 			}
7203*c54f35caSApple OSS Distributions 			if (fPowerStates[i].capabilityFlags & kIOPMLowPower) {
7204*c54f35caSApple OSS Distributions 				bits |= kPMReportLowPower;
7205*c54f35caSApple OSS Distributions 			}
7206*c54f35caSApple OSS Distributions 
7207*c54f35caSApple OSS Distributions 			STATEREPORT_SETSTATEID(fReportBuf, i, ((bits & 0xff) << 8) |
7208*c54f35caSApple OSS Distributions 			    ((StateOrder(fMaxPowerState) & 0xf) << 4) | (StateOrder(i) & 0xf));
7209*c54f35caSApple OSS Distributions 		}
7210*c54f35caSApple OSS Distributions 		ts = mach_absolute_time();
7211*c54f35caSApple OSS Distributions 		STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
7212*c54f35caSApple OSS Distributions 		break;
7213*c54f35caSApple OSS Distributions 
7214*c54f35caSApple OSS Distributions 	case kIOReportDisable:
7215*c54f35caSApple OSS Distributions 		if (fReportClientCnt == 0) {
7216*c54f35caSApple OSS Distributions 			rc = kIOReturnBadArgument;
7217*c54f35caSApple OSS Distributions 			break;
7218*c54f35caSApple OSS Distributions 		}
7219*c54f35caSApple OSS Distributions 		if (fReportClientCnt == 1) {
7220*c54f35caSApple OSS Distributions 			IOFreeData(fReportBuf, STATEREPORT_BUFSIZE(fNumberOfPowerStates));
7221*c54f35caSApple OSS Distributions 			fReportBuf = NULL;
7222*c54f35caSApple OSS Distributions 		}
7223*c54f35caSApple OSS Distributions 		fReportClientCnt--;
7224*c54f35caSApple OSS Distributions 		break;
7225*c54f35caSApple OSS Distributions 
7226*c54f35caSApple OSS Distributions 	case kIOReportGetDimensions:
7227*c54f35caSApple OSS Distributions 		if (fReportBuf) {
7228*c54f35caSApple OSS Distributions 			STATEREPORT_UPDATERES(fReportBuf, kIOReportGetDimensions, result);
7229*c54f35caSApple OSS Distributions 		}
7230*c54f35caSApple OSS Distributions 		break;
7231*c54f35caSApple OSS Distributions 	}
7232*c54f35caSApple OSS Distributions 
7233*c54f35caSApple OSS Distributions 	PM_UNLOCK();
7234*c54f35caSApple OSS Distributions 
7235*c54f35caSApple OSS Distributions 	return rc;
7236*c54f35caSApple OSS Distributions }
7237*c54f35caSApple OSS Distributions 
7238*c54f35caSApple OSS Distributions //*********************************************************************************
7239*c54f35caSApple OSS Distributions //  updatePowerStateReport
7240*c54f35caSApple OSS Distributions //
7241*c54f35caSApple OSS Distributions //  Updates the IOStateReport for kPMPowerStateChannel
7242*c54f35caSApple OSS Distributions //*********************************************************************************
7243*c54f35caSApple OSS Distributions IOReturn
updatePowerStatesReport(IOReportConfigureAction action,void * result,void * destination)7244*c54f35caSApple OSS Distributions IOService::updatePowerStatesReport( IOReportConfigureAction action, void *result, void *destination )
7245*c54f35caSApple OSS Distributions {
7246*c54f35caSApple OSS Distributions 	uint32_t size2cpy;
7247*c54f35caSApple OSS Distributions 	void *data2cpy;
7248*c54f35caSApple OSS Distributions 	uint64_t ts;
7249*c54f35caSApple OSS Distributions 	IOReturn rc = kIOReturnSuccess;
7250*c54f35caSApple OSS Distributions 	IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7251*c54f35caSApple OSS Distributions 
7252*c54f35caSApple OSS Distributions 
7253*c54f35caSApple OSS Distributions 	if (!pwrMgt) {
7254*c54f35caSApple OSS Distributions 		return kIOReturnUnsupported;
7255*c54f35caSApple OSS Distributions 	}
7256*c54f35caSApple OSS Distributions 	if (!fNumberOfPowerStates) {
7257*c54f35caSApple OSS Distributions 		return kIOReturnSuccess;
7258*c54f35caSApple OSS Distributions 	}
7259*c54f35caSApple OSS Distributions 
7260*c54f35caSApple OSS Distributions 	if (!result || !dest) {
7261*c54f35caSApple OSS Distributions 		return kIOReturnBadArgument;
7262*c54f35caSApple OSS Distributions 	}
7263*c54f35caSApple OSS Distributions 	PM_LOCK();
7264*c54f35caSApple OSS Distributions 
7265*c54f35caSApple OSS Distributions 	switch (action) {
7266*c54f35caSApple OSS Distributions 	case kIOReportCopyChannelData:
7267*c54f35caSApple OSS Distributions 		if (!fReportBuf) {
7268*c54f35caSApple OSS Distributions 			rc = kIOReturnNotOpen;
7269*c54f35caSApple OSS Distributions 			break;
7270*c54f35caSApple OSS Distributions 		}
7271*c54f35caSApple OSS Distributions 
7272*c54f35caSApple OSS Distributions 		ts = mach_absolute_time();
7273*c54f35caSApple OSS Distributions 		STATEREPORT_UPDATEPREP(fReportBuf, ts, data2cpy, size2cpy);
7274*c54f35caSApple OSS Distributions 		if (size2cpy > (dest->getCapacity() - dest->getLength())) {
7275*c54f35caSApple OSS Distributions 			rc = kIOReturnOverrun;
7276*c54f35caSApple OSS Distributions 			break;
7277*c54f35caSApple OSS Distributions 		}
7278*c54f35caSApple OSS Distributions 
7279*c54f35caSApple OSS Distributions 		STATEREPORT_UPDATERES(fReportBuf, kIOReportCopyChannelData, result);
7280*c54f35caSApple OSS Distributions 		dest->appendBytes(data2cpy, size2cpy);
7281*c54f35caSApple OSS Distributions 		break;
7282*c54f35caSApple OSS Distributions 
7283*c54f35caSApple OSS Distributions 	default:
7284*c54f35caSApple OSS Distributions 		break;
7285*c54f35caSApple OSS Distributions 	}
7286*c54f35caSApple OSS Distributions 
7287*c54f35caSApple OSS Distributions 	PM_UNLOCK();
7288*c54f35caSApple OSS Distributions 
7289*c54f35caSApple OSS Distributions 	return rc;
7290*c54f35caSApple OSS Distributions }
7291*c54f35caSApple OSS Distributions 
7292*c54f35caSApple OSS Distributions //*********************************************************************************
7293*c54f35caSApple OSS Distributions //  configureSimplePowerReport
7294*c54f35caSApple OSS Distributions //
7295*c54f35caSApple OSS Distributions //  Configures the IOSimpleReport for given channel id
7296*c54f35caSApple OSS Distributions //*********************************************************************************
7297*c54f35caSApple OSS Distributions IOReturn
configureSimplePowerReport(IOReportConfigureAction action,void * result)7298*c54f35caSApple OSS Distributions IOService::configureSimplePowerReport(IOReportConfigureAction action, void *result )
7299*c54f35caSApple OSS Distributions {
7300*c54f35caSApple OSS Distributions 	IOReturn rc = kIOReturnSuccess;
7301*c54f35caSApple OSS Distributions 
7302*c54f35caSApple OSS Distributions 	if (!pwrMgt) {
7303*c54f35caSApple OSS Distributions 		return kIOReturnUnsupported;
7304*c54f35caSApple OSS Distributions 	}
7305*c54f35caSApple OSS Distributions 
7306*c54f35caSApple OSS Distributions 	if (!fNumberOfPowerStates) {
7307*c54f35caSApple OSS Distributions 		return rc;
7308*c54f35caSApple OSS Distributions 	}
7309*c54f35caSApple OSS Distributions 
7310*c54f35caSApple OSS Distributions 	switch (action) {
7311*c54f35caSApple OSS Distributions 	case kIOReportEnable:
7312*c54f35caSApple OSS Distributions 	case kIOReportDisable:
7313*c54f35caSApple OSS Distributions 		break;
7314*c54f35caSApple OSS Distributions 
7315*c54f35caSApple OSS Distributions 	case kIOReportGetDimensions:
7316*c54f35caSApple OSS Distributions 		SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
7317*c54f35caSApple OSS Distributions 		break;
7318*c54f35caSApple OSS Distributions 	}
7319*c54f35caSApple OSS Distributions 
7320*c54f35caSApple OSS Distributions 
7321*c54f35caSApple OSS Distributions 	return rc;
7322*c54f35caSApple OSS Distributions }
7323*c54f35caSApple OSS Distributions 
7324*c54f35caSApple OSS Distributions //*********************************************************************************
7325*c54f35caSApple OSS Distributions //  updateSimplePowerReport
7326*c54f35caSApple OSS Distributions //
7327*c54f35caSApple OSS Distributions //  Updates the IOSimpleReport for the given chanel id
7328*c54f35caSApple OSS Distributions //*********************************************************************************
7329*c54f35caSApple OSS Distributions IOReturn
updateSimplePowerReport(IOReportConfigureAction action,void * result,void * destination)7330*c54f35caSApple OSS Distributions IOService::updateSimplePowerReport( IOReportConfigureAction action, void *result, void *destination )
7331*c54f35caSApple OSS Distributions {
7332*c54f35caSApple OSS Distributions 	uint32_t size2cpy;
7333*c54f35caSApple OSS Distributions 	void *data2cpy;
7334*c54f35caSApple OSS Distributions 	uint64_t buf[SIMPLEREPORT_BUFSIZE / sizeof(uint64_t) + 1]; // Force a 8-byte alignment
7335*c54f35caSApple OSS Distributions 	IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7336*c54f35caSApple OSS Distributions 	IOReturn rc = kIOReturnSuccess;
7337*c54f35caSApple OSS Distributions 	unsigned bits = 0;
7338*c54f35caSApple OSS Distributions 
7339*c54f35caSApple OSS Distributions 
7340*c54f35caSApple OSS Distributions 	if (!pwrMgt) {
7341*c54f35caSApple OSS Distributions 		return kIOReturnUnsupported;
7342*c54f35caSApple OSS Distributions 	}
7343*c54f35caSApple OSS Distributions 	if (!result || !dest) {
7344*c54f35caSApple OSS Distributions 		return kIOReturnBadArgument;
7345*c54f35caSApple OSS Distributions 	}
7346*c54f35caSApple OSS Distributions 
7347*c54f35caSApple OSS Distributions 	if (!fNumberOfPowerStates) {
7348*c54f35caSApple OSS Distributions 		return rc;
7349*c54f35caSApple OSS Distributions 	}
7350*c54f35caSApple OSS Distributions 	PM_LOCK();
7351*c54f35caSApple OSS Distributions 
7352*c54f35caSApple OSS Distributions 	switch (action) {
7353*c54f35caSApple OSS Distributions 	case kIOReportCopyChannelData:
7354*c54f35caSApple OSS Distributions 
7355*c54f35caSApple OSS Distributions 		SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), kPMCurrStateChID, kIOReportCategoryPower);
7356*c54f35caSApple OSS Distributions 
7357*c54f35caSApple OSS Distributions 		if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMPowerOn) {
7358*c54f35caSApple OSS Distributions 			bits |= kPMReportPowerOn;
7359*c54f35caSApple OSS Distributions 		}
7360*c54f35caSApple OSS Distributions 		if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMDeviceUsable) {
7361*c54f35caSApple OSS Distributions 			bits |= kPMReportDeviceUsable;
7362*c54f35caSApple OSS Distributions 		}
7363*c54f35caSApple OSS Distributions 		if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMLowPower) {
7364*c54f35caSApple OSS Distributions 			bits |= kPMReportLowPower;
7365*c54f35caSApple OSS Distributions 		}
7366*c54f35caSApple OSS Distributions 
7367*c54f35caSApple OSS Distributions 
7368*c54f35caSApple OSS Distributions 		SIMPLEREPORT_SETVALUE(buf, ((bits & 0xff) << 8) | ((StateOrder(fMaxPowerState) & 0xf) << 4) |
7369*c54f35caSApple OSS Distributions 		    (StateOrder(fCurrentPowerState) & 0xf));
7370*c54f35caSApple OSS Distributions 
7371*c54f35caSApple OSS Distributions 		SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
7372*c54f35caSApple OSS Distributions 		if (size2cpy > (dest->getCapacity() - dest->getLength())) {
7373*c54f35caSApple OSS Distributions 			rc = kIOReturnOverrun;
7374*c54f35caSApple OSS Distributions 			break;
7375*c54f35caSApple OSS Distributions 		}
7376*c54f35caSApple OSS Distributions 
7377*c54f35caSApple OSS Distributions 		SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
7378*c54f35caSApple OSS Distributions 		dest->appendBytes(data2cpy, size2cpy);
7379*c54f35caSApple OSS Distributions 		break;
7380*c54f35caSApple OSS Distributions 
7381*c54f35caSApple OSS Distributions 	default:
7382*c54f35caSApple OSS Distributions 		break;
7383*c54f35caSApple OSS Distributions 	}
7384*c54f35caSApple OSS Distributions 
7385*c54f35caSApple OSS Distributions 	PM_UNLOCK();
7386*c54f35caSApple OSS Distributions 
7387*c54f35caSApple OSS Distributions 	return rc;
7388*c54f35caSApple OSS Distributions }
7389*c54f35caSApple OSS Distributions 
7390*c54f35caSApple OSS Distributions 
7391*c54f35caSApple OSS Distributions 
7392*c54f35caSApple OSS Distributions // MARK: -
7393*c54f35caSApple OSS Distributions // MARK: Driver Overrides
7394*c54f35caSApple OSS Distributions 
7395*c54f35caSApple OSS Distributions //*********************************************************************************
7396*c54f35caSApple OSS Distributions // [public] setPowerState
7397*c54f35caSApple OSS Distributions //
7398*c54f35caSApple OSS Distributions // Does nothing here.  This should be implemented in a subclass driver.
7399*c54f35caSApple OSS Distributions //*********************************************************************************
7400*c54f35caSApple OSS Distributions 
7401*c54f35caSApple OSS Distributions IOReturn
setPowerState(unsigned long powerStateOrdinal,IOService * whatDevice)7402*c54f35caSApple OSS Distributions IOService::setPowerState(
7403*c54f35caSApple OSS Distributions 	unsigned long powerStateOrdinal, IOService * whatDevice )
7404*c54f35caSApple OSS Distributions {
7405*c54f35caSApple OSS Distributions 	return IOPMNoErr;
7406*c54f35caSApple OSS Distributions }
7407*c54f35caSApple OSS Distributions 
7408*c54f35caSApple OSS Distributions //*********************************************************************************
7409*c54f35caSApple OSS Distributions // [public] maxCapabilityForDomainState
7410*c54f35caSApple OSS Distributions //
7411*c54f35caSApple OSS Distributions // Finds the highest power state in the array whose input power requirement
7412*c54f35caSApple OSS Distributions // is equal to the input parameter. Where a more intelligent decision is
7413*c54f35caSApple OSS Distributions // possible, override this in the subclassed driver.
7414*c54f35caSApple OSS Distributions //*********************************************************************************
7415*c54f35caSApple OSS Distributions 
7416*c54f35caSApple OSS Distributions IOPMPowerStateIndex
getPowerStateForDomainFlags(IOPMPowerFlags flags)7417*c54f35caSApple OSS Distributions IOService::getPowerStateForDomainFlags( IOPMPowerFlags flags )
7418*c54f35caSApple OSS Distributions {
7419*c54f35caSApple OSS Distributions 	IOPMPowerStateIndex stateIndex;
7420*c54f35caSApple OSS Distributions 
7421*c54f35caSApple OSS Distributions 	if (!fNumberOfPowerStates) {
7422*c54f35caSApple OSS Distributions 		return kPowerStateZero;
7423*c54f35caSApple OSS Distributions 	}
7424*c54f35caSApple OSS Distributions 
7425*c54f35caSApple OSS Distributions 	for (long order = fNumberOfPowerStates - 1; order >= 0; order--) {
7426*c54f35caSApple OSS Distributions 		stateIndex = fPowerStates[order].stateOrderToIndex;
7427*c54f35caSApple OSS Distributions 
7428*c54f35caSApple OSS Distributions 		if ((flags & fPowerStates[stateIndex].inputPowerFlags) ==
7429*c54f35caSApple OSS Distributions 		    fPowerStates[stateIndex].inputPowerFlags) {
7430*c54f35caSApple OSS Distributions 			return stateIndex;
7431*c54f35caSApple OSS Distributions 		}
7432*c54f35caSApple OSS Distributions 	}
7433*c54f35caSApple OSS Distributions 	return kPowerStateZero;
7434*c54f35caSApple OSS Distributions }
7435*c54f35caSApple OSS Distributions 
7436*c54f35caSApple OSS Distributions unsigned long
maxCapabilityForDomainState(IOPMPowerFlags domainState)7437*c54f35caSApple OSS Distributions IOService::maxCapabilityForDomainState( IOPMPowerFlags domainState )
7438*c54f35caSApple OSS Distributions {
7439*c54f35caSApple OSS Distributions 	return getPowerStateForDomainFlags(domainState);
7440*c54f35caSApple OSS Distributions }
7441*c54f35caSApple OSS Distributions 
7442*c54f35caSApple OSS Distributions //*********************************************************************************
7443*c54f35caSApple OSS Distributions // [public] initialPowerStateForDomainState
7444*c54f35caSApple OSS Distributions //
7445*c54f35caSApple OSS Distributions // Called to query the power state for the initial power transition.
7446*c54f35caSApple OSS Distributions //*********************************************************************************
7447*c54f35caSApple OSS Distributions 
7448*c54f35caSApple OSS Distributions unsigned long
initialPowerStateForDomainState(IOPMPowerFlags domainState)7449*c54f35caSApple OSS Distributions IOService::initialPowerStateForDomainState( IOPMPowerFlags domainState )
7450*c54f35caSApple OSS Distributions {
7451*c54f35caSApple OSS Distributions 	if (fResetPowerStateOnWake && (domainState & kIOPMRootDomainState)) {
7452*c54f35caSApple OSS Distributions 		// Return lowest power state for any root power domain changes
7453*c54f35caSApple OSS Distributions 		return kPowerStateZero;
7454*c54f35caSApple OSS Distributions 	}
7455*c54f35caSApple OSS Distributions 
7456*c54f35caSApple OSS Distributions 	return getPowerStateForDomainFlags(domainState);
7457*c54f35caSApple OSS Distributions }
7458*c54f35caSApple OSS Distributions 
7459*c54f35caSApple OSS Distributions //*********************************************************************************
7460*c54f35caSApple OSS Distributions // [public] powerStateForDomainState
7461*c54f35caSApple OSS Distributions //
7462*c54f35caSApple OSS Distributions // This method is not called from PM.
7463*c54f35caSApple OSS Distributions //*********************************************************************************
7464*c54f35caSApple OSS Distributions 
7465*c54f35caSApple OSS Distributions unsigned long
powerStateForDomainState(IOPMPowerFlags domainState)7466*c54f35caSApple OSS Distributions IOService::powerStateForDomainState( IOPMPowerFlags domainState )
7467*c54f35caSApple OSS Distributions {
7468*c54f35caSApple OSS Distributions 	return getPowerStateForDomainFlags(domainState);
7469*c54f35caSApple OSS Distributions }
7470*c54f35caSApple OSS Distributions 
7471*c54f35caSApple OSS Distributions #ifndef __LP64__
7472*c54f35caSApple OSS Distributions //*********************************************************************************
7473*c54f35caSApple OSS Distributions // [deprecated] didYouWakeSystem
7474*c54f35caSApple OSS Distributions //
7475*c54f35caSApple OSS Distributions // Does nothing here.  This should be implemented in a subclass driver.
7476*c54f35caSApple OSS Distributions //*********************************************************************************
7477*c54f35caSApple OSS Distributions 
7478*c54f35caSApple OSS Distributions bool
didYouWakeSystem(void)7479*c54f35caSApple OSS Distributions IOService::didYouWakeSystem( void )
7480*c54f35caSApple OSS Distributions {
7481*c54f35caSApple OSS Distributions 	return false;
7482*c54f35caSApple OSS Distributions }
7483*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
7484*c54f35caSApple OSS Distributions 
7485*c54f35caSApple OSS Distributions //*********************************************************************************
7486*c54f35caSApple OSS Distributions // [public] powerStateWillChangeTo
7487*c54f35caSApple OSS Distributions //
7488*c54f35caSApple OSS Distributions // Does nothing here.  This should be implemented in a subclass driver.
7489*c54f35caSApple OSS Distributions //*********************************************************************************
7490*c54f35caSApple OSS Distributions 
7491*c54f35caSApple OSS Distributions IOReturn
powerStateWillChangeTo(IOPMPowerFlags,unsigned long,IOService *)7492*c54f35caSApple OSS Distributions IOService::powerStateWillChangeTo( IOPMPowerFlags, unsigned long, IOService * )
7493*c54f35caSApple OSS Distributions {
7494*c54f35caSApple OSS Distributions 	return kIOPMAckImplied;
7495*c54f35caSApple OSS Distributions }
7496*c54f35caSApple OSS Distributions 
7497*c54f35caSApple OSS Distributions //*********************************************************************************
7498*c54f35caSApple OSS Distributions // [public] powerStateDidChangeTo
7499*c54f35caSApple OSS Distributions //
7500*c54f35caSApple OSS Distributions // Does nothing here.  This should be implemented in a subclass driver.
7501*c54f35caSApple OSS Distributions //*********************************************************************************
7502*c54f35caSApple OSS Distributions 
7503*c54f35caSApple OSS Distributions IOReturn
powerStateDidChangeTo(IOPMPowerFlags,unsigned long,IOService *)7504*c54f35caSApple OSS Distributions IOService::powerStateDidChangeTo( IOPMPowerFlags, unsigned long, IOService * )
7505*c54f35caSApple OSS Distributions {
7506*c54f35caSApple OSS Distributions 	return kIOPMAckImplied;
7507*c54f35caSApple OSS Distributions }
7508*c54f35caSApple OSS Distributions 
7509*c54f35caSApple OSS Distributions //*********************************************************************************
7510*c54f35caSApple OSS Distributions // [protected] powerChangeDone
7511*c54f35caSApple OSS Distributions //
7512*c54f35caSApple OSS Distributions // Called from PM work loop thread.
7513*c54f35caSApple OSS Distributions // Does nothing here.  This should be implemented in a subclass policy-maker.
7514*c54f35caSApple OSS Distributions //*********************************************************************************
7515*c54f35caSApple OSS Distributions 
7516*c54f35caSApple OSS Distributions void
powerChangeDone(unsigned long)7517*c54f35caSApple OSS Distributions IOService::powerChangeDone( unsigned long )
7518*c54f35caSApple OSS Distributions {
7519*c54f35caSApple OSS Distributions }
7520*c54f35caSApple OSS Distributions 
7521*c54f35caSApple OSS Distributions #ifndef __LP64__
7522*c54f35caSApple OSS Distributions //*********************************************************************************
7523*c54f35caSApple OSS Distributions // [deprecated] newTemperature
7524*c54f35caSApple OSS Distributions //
7525*c54f35caSApple OSS Distributions // Does nothing here.  This should be implemented in a subclass driver.
7526*c54f35caSApple OSS Distributions //*********************************************************************************
7527*c54f35caSApple OSS Distributions 
7528*c54f35caSApple OSS Distributions IOReturn
newTemperature(long currentTemp,IOService * whichZone)7529*c54f35caSApple OSS Distributions IOService::newTemperature( long currentTemp, IOService * whichZone )
7530*c54f35caSApple OSS Distributions {
7531*c54f35caSApple OSS Distributions 	return IOPMNoErr;
7532*c54f35caSApple OSS Distributions }
7533*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
7534*c54f35caSApple OSS Distributions 
7535*c54f35caSApple OSS Distributions //*********************************************************************************
7536*c54f35caSApple OSS Distributions // [public] systemWillShutdown
7537*c54f35caSApple OSS Distributions //
7538*c54f35caSApple OSS Distributions // System shutdown and restart notification.
7539*c54f35caSApple OSS Distributions //*********************************************************************************
7540*c54f35caSApple OSS Distributions 
7541*c54f35caSApple OSS Distributions void
systemWillShutdown(IOOptionBits specifier)7542*c54f35caSApple OSS Distributions IOService::systemWillShutdown( IOOptionBits specifier )
7543*c54f35caSApple OSS Distributions {
7544*c54f35caSApple OSS Distributions 	IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
7545*c54f35caSApple OSS Distributions 	if (rootDomain) {
7546*c54f35caSApple OSS Distributions 		rootDomain->acknowledgeSystemWillShutdown( this );
7547*c54f35caSApple OSS Distributions 	}
7548*c54f35caSApple OSS Distributions }
7549*c54f35caSApple OSS Distributions 
7550*c54f35caSApple OSS Distributions // MARK: -
7551*c54f35caSApple OSS Distributions // MARK: PM State Machine
7552*c54f35caSApple OSS Distributions 
7553*c54f35caSApple OSS Distributions //*********************************************************************************
7554*c54f35caSApple OSS Distributions // [private static] acquirePMRequest
7555*c54f35caSApple OSS Distributions //*********************************************************************************
7556*c54f35caSApple OSS Distributions 
7557*c54f35caSApple OSS Distributions IOPMRequest *
acquirePMRequest(IOService * target,IOOptionBits requestType,IOPMRequest * active)7558*c54f35caSApple OSS Distributions IOService::acquirePMRequest( IOService * target, IOOptionBits requestType,
7559*c54f35caSApple OSS Distributions     IOPMRequest * active )
7560*c54f35caSApple OSS Distributions {
7561*c54f35caSApple OSS Distributions 	IOPMRequest * request;
7562*c54f35caSApple OSS Distributions 
7563*c54f35caSApple OSS Distributions 	assert(target);
7564*c54f35caSApple OSS Distributions 
7565*c54f35caSApple OSS Distributions 	request = IOPMRequest::create();
7566*c54f35caSApple OSS Distributions 	if (request) {
7567*c54f35caSApple OSS Distributions 		request->init( target, requestType );
7568*c54f35caSApple OSS Distributions 		if (active) {
7569*c54f35caSApple OSS Distributions 			IOPMRequest * root = active->getRootRequest();
7570*c54f35caSApple OSS Distributions 			if (root) {
7571*c54f35caSApple OSS Distributions 				request->attachRootRequest(root);
7572*c54f35caSApple OSS Distributions 			}
7573*c54f35caSApple OSS Distributions 		}
7574*c54f35caSApple OSS Distributions 	} else {
7575*c54f35caSApple OSS Distributions 		PM_ERROR("%s: No memory for PM request type 0x%x\n",
7576*c54f35caSApple OSS Distributions 		    target->getName(), (uint32_t) requestType);
7577*c54f35caSApple OSS Distributions 	}
7578*c54f35caSApple OSS Distributions 	return request;
7579*c54f35caSApple OSS Distributions }
7580*c54f35caSApple OSS Distributions 
7581*c54f35caSApple OSS Distributions //*********************************************************************************
7582*c54f35caSApple OSS Distributions // [private static] releasePMRequest
7583*c54f35caSApple OSS Distributions //*********************************************************************************
7584*c54f35caSApple OSS Distributions 
7585*c54f35caSApple OSS Distributions void
releasePMRequest(IOPMRequest * request)7586*c54f35caSApple OSS Distributions IOService::releasePMRequest( IOPMRequest * request )
7587*c54f35caSApple OSS Distributions {
7588*c54f35caSApple OSS Distributions 	if (request) {
7589*c54f35caSApple OSS Distributions 		request->reset();
7590*c54f35caSApple OSS Distributions 		request->release();
7591*c54f35caSApple OSS Distributions 	}
7592*c54f35caSApple OSS Distributions }
7593*c54f35caSApple OSS Distributions 
7594*c54f35caSApple OSS Distributions //*********************************************************************************
7595*c54f35caSApple OSS Distributions // [private static] submitPMRequest
7596*c54f35caSApple OSS Distributions //*********************************************************************************
7597*c54f35caSApple OSS Distributions 
7598*c54f35caSApple OSS Distributions void
submitPMRequest(IOPMRequest * request)7599*c54f35caSApple OSS Distributions IOService::submitPMRequest( IOPMRequest * request )
7600*c54f35caSApple OSS Distributions {
7601*c54f35caSApple OSS Distributions 	assert( request );
7602*c54f35caSApple OSS Distributions 	assert( gIOPMReplyQueue );
7603*c54f35caSApple OSS Distributions 	assert( gIOPMRequestQueue );
7604*c54f35caSApple OSS Distributions 
7605*c54f35caSApple OSS Distributions 	PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
7606*c54f35caSApple OSS Distributions 	    (long)request->getType(), OBFUSCATE(request),
7607*c54f35caSApple OSS Distributions 	    OBFUSCATE(request->getTarget()), request->getTarget()->getName(),
7608*c54f35caSApple OSS Distributions 	    OBFUSCATE(request->fArg0),
7609*c54f35caSApple OSS Distributions 	    OBFUSCATE(request->fArg1), OBFUSCATE(request->fArg2));
7610*c54f35caSApple OSS Distributions 
7611*c54f35caSApple OSS Distributions 	if (request->isReplyType()) {
7612*c54f35caSApple OSS Distributions 		gIOPMReplyQueue->queuePMRequest( request );
7613*c54f35caSApple OSS Distributions 	} else {
7614*c54f35caSApple OSS Distributions 		gIOPMRequestQueue->queuePMRequest( request );
7615*c54f35caSApple OSS Distributions 	}
7616*c54f35caSApple OSS Distributions }
7617*c54f35caSApple OSS Distributions 
7618*c54f35caSApple OSS Distributions void
submitPMRequests(IOPMRequest ** requests,IOItemCount count)7619*c54f35caSApple OSS Distributions IOService::submitPMRequests( IOPMRequest ** requests, IOItemCount count )
7620*c54f35caSApple OSS Distributions {
7621*c54f35caSApple OSS Distributions 	assert( requests );
7622*c54f35caSApple OSS Distributions 	assert( count > 0 );
7623*c54f35caSApple OSS Distributions 	assert( gIOPMRequestQueue );
7624*c54f35caSApple OSS Distributions 
7625*c54f35caSApple OSS Distributions 	for (IOItemCount i = 0; i < count; i++) {
7626*c54f35caSApple OSS Distributions 		IOPMRequest * req = requests[i];
7627*c54f35caSApple OSS Distributions 		PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
7628*c54f35caSApple OSS Distributions 		    (long)req->getType(), OBFUSCATE(req),
7629*c54f35caSApple OSS Distributions 		    OBFUSCATE(req->getTarget()), req->getTarget()->getName(),
7630*c54f35caSApple OSS Distributions 		    OBFUSCATE(req->fArg0),
7631*c54f35caSApple OSS Distributions 		    OBFUSCATE(req->fArg1), OBFUSCATE(req->fArg2));
7632*c54f35caSApple OSS Distributions 	}
7633*c54f35caSApple OSS Distributions 
7634*c54f35caSApple OSS Distributions 	gIOPMRequestQueue->queuePMRequestChain( requests, count );
7635*c54f35caSApple OSS Distributions }
7636*c54f35caSApple OSS Distributions 
7637*c54f35caSApple OSS Distributions //*********************************************************************************
7638*c54f35caSApple OSS Distributions // [private] actionPMRequestQueue
7639*c54f35caSApple OSS Distributions //
7640*c54f35caSApple OSS Distributions // IOPMRequestQueue::checkForWork() passing a new request to the request target.
7641*c54f35caSApple OSS Distributions //*********************************************************************************
7642*c54f35caSApple OSS Distributions 
7643*c54f35caSApple OSS Distributions bool
actionPMRequestQueue(IOPMRequest * request,IOPMRequestQueue * queue)7644*c54f35caSApple OSS Distributions IOService::actionPMRequestQueue(
7645*c54f35caSApple OSS Distributions 	IOPMRequest *       request,
7646*c54f35caSApple OSS Distributions 	IOPMRequestQueue *  queue )
7647*c54f35caSApple OSS Distributions {
7648*c54f35caSApple OSS Distributions 	bool more;
7649*c54f35caSApple OSS Distributions 
7650*c54f35caSApple OSS Distributions 	if (initialized) {
7651*c54f35caSApple OSS Distributions 		// Work queue will immediately execute the request if the per-service
7652*c54f35caSApple OSS Distributions 		// request queue is empty. Note pwrMgt is the target's IOServicePM.
7653*c54f35caSApple OSS Distributions 
7654*c54f35caSApple OSS Distributions 		more = gIOPMWorkQueue->queuePMRequest(request, pwrMgt);
7655*c54f35caSApple OSS Distributions 	} else {
7656*c54f35caSApple OSS Distributions 		// Calling PM without PMinit() is not allowed, fail the request.
7657*c54f35caSApple OSS Distributions 		// Need to signal more when completing attached requests.
7658*c54f35caSApple OSS Distributions 
7659*c54f35caSApple OSS Distributions 		PM_LOG("%s: PM not initialized\n", getName());
7660*c54f35caSApple OSS Distributions 		PM_LOG1("[- %02x] %p [%p %s] !initialized\n",
7661*c54f35caSApple OSS Distributions 		    request->getType(), OBFUSCATE(request),
7662*c54f35caSApple OSS Distributions 		    OBFUSCATE(this), getName());
7663*c54f35caSApple OSS Distributions 
7664*c54f35caSApple OSS Distributions 		more = gIOPMCompletionQueue->queuePMRequest(request);
7665*c54f35caSApple OSS Distributions 		if (more) {
7666*c54f35caSApple OSS Distributions 			gIOPMWorkQueue->incrementProducerCount();
7667*c54f35caSApple OSS Distributions 		}
7668*c54f35caSApple OSS Distributions 	}
7669*c54f35caSApple OSS Distributions 
7670*c54f35caSApple OSS Distributions 	return more;
7671*c54f35caSApple OSS Distributions }
7672*c54f35caSApple OSS Distributions 
7673*c54f35caSApple OSS Distributions //*********************************************************************************
7674*c54f35caSApple OSS Distributions // [private] actionPMCompletionQueue
7675*c54f35caSApple OSS Distributions //
7676*c54f35caSApple OSS Distributions // IOPMCompletionQueue::checkForWork() passing a completed request to the
7677*c54f35caSApple OSS Distributions // request target.
7678*c54f35caSApple OSS Distributions //*********************************************************************************
7679*c54f35caSApple OSS Distributions 
7680*c54f35caSApple OSS Distributions bool
actionPMCompletionQueue(IOPMRequest * request,IOPMCompletionQueue * queue)7681*c54f35caSApple OSS Distributions IOService::actionPMCompletionQueue(
7682*c54f35caSApple OSS Distributions 	IOPMRequest *         request,
7683*c54f35caSApple OSS Distributions 	IOPMCompletionQueue * queue )
7684*c54f35caSApple OSS Distributions {
7685*c54f35caSApple OSS Distributions 	bool            more = (request->getNextRequest() != NULL);
7686*c54f35caSApple OSS Distributions 	IOPMRequest *   root = request->getRootRequest();
7687*c54f35caSApple OSS Distributions 
7688*c54f35caSApple OSS Distributions 	if (root && (root != request)) {
7689*c54f35caSApple OSS Distributions 		more = true;
7690*c54f35caSApple OSS Distributions 	}
7691*c54f35caSApple OSS Distributions 	if (more) {
7692*c54f35caSApple OSS Distributions 		gIOPMWorkQueue->incrementProducerCount();
7693*c54f35caSApple OSS Distributions 	}
7694*c54f35caSApple OSS Distributions 
7695*c54f35caSApple OSS Distributions 	releasePMRequest( request );
7696*c54f35caSApple OSS Distributions 	return more;
7697*c54f35caSApple OSS Distributions }
7698*c54f35caSApple OSS Distributions 
7699*c54f35caSApple OSS Distributions //*********************************************************************************
7700*c54f35caSApple OSS Distributions // [private] actionPMWorkQueueRetire
7701*c54f35caSApple OSS Distributions //
7702*c54f35caSApple OSS Distributions // IOPMWorkQueue::checkForWork() passing a retired request to the request target.
7703*c54f35caSApple OSS Distributions //*********************************************************************************
7704*c54f35caSApple OSS Distributions 
7705*c54f35caSApple OSS Distributions bool
actionPMWorkQueueRetire(IOPMRequest * request,IOPMWorkQueue * queue)7706*c54f35caSApple OSS Distributions IOService::actionPMWorkQueueRetire( IOPMRequest * request, IOPMWorkQueue * queue )
7707*c54f35caSApple OSS Distributions {
7708*c54f35caSApple OSS Distributions 	assert(request && queue);
7709*c54f35caSApple OSS Distributions 
7710*c54f35caSApple OSS Distributions 	PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
7711*c54f35caSApple OSS Distributions 	    request->getType(), OBFUSCATE(request),
7712*c54f35caSApple OSS Distributions 	    OBFUSCATE(this), getName(),
7713*c54f35caSApple OSS Distributions 	    fMachineState, gIOPMBusyRequestCount);
7714*c54f35caSApple OSS Distributions 
7715*c54f35caSApple OSS Distributions 	// Catch requests created by idleTimerExpired()
7716*c54f35caSApple OSS Distributions 	if (request->getType() == kIOPMRequestTypeActivityTickle) {
7717*c54f35caSApple OSS Distributions 		uint32_t tickleFlags = (uint32_t)(uintptr_t) request->fArg1;
7718*c54f35caSApple OSS Distributions 
7719*c54f35caSApple OSS Distributions 		if ((tickleFlags & kTickleTypePowerDrop) && fIdleTimerPeriod) {
7720*c54f35caSApple OSS Distributions 			restartIdleTimer();
7721*c54f35caSApple OSS Distributions 		} else if (tickleFlags == (kTickleTypeActivity | kTickleTypePowerRise)) {
7722*c54f35caSApple OSS Distributions 			// Invalidate any idle power drop that got queued while
7723*c54f35caSApple OSS Distributions 			// processing this request.
7724*c54f35caSApple OSS Distributions 			fIdleTimerGeneration++;
7725*c54f35caSApple OSS Distributions 		}
7726*c54f35caSApple OSS Distributions 	}
7727*c54f35caSApple OSS Distributions 
7728*c54f35caSApple OSS Distributions 	// When the completed request is linked, tell work queue there is
7729*c54f35caSApple OSS Distributions 	// more work pending.
7730*c54f35caSApple OSS Distributions 
7731*c54f35caSApple OSS Distributions 	return gIOPMCompletionQueue->queuePMRequest( request );
7732*c54f35caSApple OSS Distributions }
7733*c54f35caSApple OSS Distributions 
7734*c54f35caSApple OSS Distributions //*********************************************************************************
7735*c54f35caSApple OSS Distributions // [private] isPMBlocked
7736*c54f35caSApple OSS Distributions //
7737*c54f35caSApple OSS Distributions // Check if machine state transition is blocked.
7738*c54f35caSApple OSS Distributions //*********************************************************************************
7739*c54f35caSApple OSS Distributions 
7740*c54f35caSApple OSS Distributions bool
isPMBlocked(IOPMRequest * request,int count)7741*c54f35caSApple OSS Distributions IOService::isPMBlocked( IOPMRequest * request, int count )
7742*c54f35caSApple OSS Distributions {
7743*c54f35caSApple OSS Distributions 	int reason = 0;
7744*c54f35caSApple OSS Distributions 
7745*c54f35caSApple OSS Distributions 	do {
7746*c54f35caSApple OSS Distributions 		if (kIOPM_Finished == fMachineState) {
7747*c54f35caSApple OSS Distributions 			break;
7748*c54f35caSApple OSS Distributions 		}
7749*c54f35caSApple OSS Distributions 
7750*c54f35caSApple OSS Distributions 		if (kIOPM_DriverThreadCallDone == fMachineState) {
7751*c54f35caSApple OSS Distributions 			// 5 = kDriverCallInformPreChange
7752*c54f35caSApple OSS Distributions 			// 6 = kDriverCallInformPostChange
7753*c54f35caSApple OSS Distributions 			// 7 = kDriverCallSetPowerState
7754*c54f35caSApple OSS Distributions 			// 8 = kRootDomainInformPreChange
7755*c54f35caSApple OSS Distributions 			if (fDriverCallBusy) {
7756*c54f35caSApple OSS Distributions 				reason = 5 + fDriverCallReason;
7757*c54f35caSApple OSS Distributions 			}
7758*c54f35caSApple OSS Distributions 			break;
7759*c54f35caSApple OSS Distributions 		}
7760*c54f35caSApple OSS Distributions 
7761*c54f35caSApple OSS Distributions 		// Waiting on driver's setPowerState() timeout.
7762*c54f35caSApple OSS Distributions 		if (fDriverTimer) {
7763*c54f35caSApple OSS Distributions 			reason = 1; break;
7764*c54f35caSApple OSS Distributions 		}
7765*c54f35caSApple OSS Distributions 
7766*c54f35caSApple OSS Distributions 		// Child or interested driver acks pending.
7767*c54f35caSApple OSS Distributions 		if (fHeadNotePendingAcks) {
7768*c54f35caSApple OSS Distributions 			reason = 2; break;
7769*c54f35caSApple OSS Distributions 		}
7770*c54f35caSApple OSS Distributions 
7771*c54f35caSApple OSS Distributions 		// Waiting on apps or priority power interest clients.
7772*c54f35caSApple OSS Distributions 		if (fResponseArray) {
7773*c54f35caSApple OSS Distributions 			reason = 3; break;
7774*c54f35caSApple OSS Distributions 		}
7775*c54f35caSApple OSS Distributions 
7776*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
7777*c54f35caSApple OSS Distributions 		// Waiting on settle timer expiration.
7778*c54f35caSApple OSS Distributions 		if (fSettleTimeUS) {
7779*c54f35caSApple OSS Distributions 			reason = 4; break;
7780*c54f35caSApple OSS Distributions 		}
7781*c54f35caSApple OSS Distributions #endif
7782*c54f35caSApple OSS Distributions 	} while (false);
7783*c54f35caSApple OSS Distributions 
7784*c54f35caSApple OSS Distributions 	fWaitReason = reason;
7785*c54f35caSApple OSS Distributions 
7786*c54f35caSApple OSS Distributions 	if (reason) {
7787*c54f35caSApple OSS Distributions 		if (count) {
7788*c54f35caSApple OSS Distributions 			PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
7789*c54f35caSApple OSS Distributions 			    request->getType(), OBFUSCATE(request),
7790*c54f35caSApple OSS Distributions 			    OBFUSCATE(this), getName(),
7791*c54f35caSApple OSS Distributions 			    fMachineState, reason);
7792*c54f35caSApple OSS Distributions 		}
7793*c54f35caSApple OSS Distributions 
7794*c54f35caSApple OSS Distributions 		return true;
7795*c54f35caSApple OSS Distributions 	}
7796*c54f35caSApple OSS Distributions 
7797*c54f35caSApple OSS Distributions 	return false;
7798*c54f35caSApple OSS Distributions }
7799*c54f35caSApple OSS Distributions 
7800*c54f35caSApple OSS Distributions //*********************************************************************************
7801*c54f35caSApple OSS Distributions // [private] actionPMWorkQueueInvoke
7802*c54f35caSApple OSS Distributions //
7803*c54f35caSApple OSS Distributions // IOPMWorkQueue::checkForWork() passing a request to the
7804*c54f35caSApple OSS Distributions // request target for execution.
7805*c54f35caSApple OSS Distributions //*********************************************************************************
7806*c54f35caSApple OSS Distributions 
7807*c54f35caSApple OSS Distributions bool
actionPMWorkQueueInvoke(IOPMRequest * request,IOPMWorkQueue * queue)7808*c54f35caSApple OSS Distributions IOService::actionPMWorkQueueInvoke( IOPMRequest * request, IOPMWorkQueue * queue )
7809*c54f35caSApple OSS Distributions {
7810*c54f35caSApple OSS Distributions 	bool    done = false;
7811*c54f35caSApple OSS Distributions 	int     loop = 0;
7812*c54f35caSApple OSS Distributions 
7813*c54f35caSApple OSS Distributions 	assert(request && queue);
7814*c54f35caSApple OSS Distributions 
7815*c54f35caSApple OSS Distributions 	while (isPMBlocked(request, loop++) == false) {
7816*c54f35caSApple OSS Distributions 		PM_LOG1("[W %02x] %p [%p %s] state %d\n",
7817*c54f35caSApple OSS Distributions 		    request->getType(), OBFUSCATE(request),
7818*c54f35caSApple OSS Distributions 		    OBFUSCATE(this), getName(), fMachineState);
7819*c54f35caSApple OSS Distributions 
7820*c54f35caSApple OSS Distributions 		gIOPMRequest = request;
7821*c54f35caSApple OSS Distributions 		gIOPMWorkInvokeCount++;
7822*c54f35caSApple OSS Distributions 
7823*c54f35caSApple OSS Distributions 		// Every PM machine states must be handled in one of the cases below.
7824*c54f35caSApple OSS Distributions 
7825*c54f35caSApple OSS Distributions 		switch (fMachineState) {
7826*c54f35caSApple OSS Distributions 		case kIOPM_Finished:
7827*c54f35caSApple OSS Distributions 			start_watchdog_timer();
7828*c54f35caSApple OSS Distributions 
7829*c54f35caSApple OSS Distributions 			executePMRequest( request );
7830*c54f35caSApple OSS Distributions 			break;
7831*c54f35caSApple OSS Distributions 
7832*c54f35caSApple OSS Distributions 		case kIOPM_OurChangeTellClientsPowerDown:
7833*c54f35caSApple OSS Distributions 			// Root domain might self cancel due to assertions.
7834*c54f35caSApple OSS Distributions 			if (IS_ROOT_DOMAIN) {
7835*c54f35caSApple OSS Distributions 				bool cancel = (bool) fDoNotPowerDown;
7836*c54f35caSApple OSS Distributions 				getPMRootDomain()->askChangeDownDone(
7837*c54f35caSApple OSS Distributions 					&fHeadNoteChangeFlags, &cancel);
7838*c54f35caSApple OSS Distributions 				fDoNotPowerDown = cancel;
7839*c54f35caSApple OSS Distributions 			}
7840*c54f35caSApple OSS Distributions 
7841*c54f35caSApple OSS Distributions 			// askChangeDown() done, was it vetoed?
7842*c54f35caSApple OSS Distributions 			if (!fDoNotPowerDown) {
7843*c54f35caSApple OSS Distributions 				// no, we can continue
7844*c54f35caSApple OSS Distributions 				OurChangeTellClientsPowerDown();
7845*c54f35caSApple OSS Distributions 			} else {
7846*c54f35caSApple OSS Distributions 				OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7847*c54f35caSApple OSS Distributions 				PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7848*c54f35caSApple OSS Distributions 				if (IS_ROOT_DOMAIN) {
7849*c54f35caSApple OSS Distributions 					// RootDomain already sent "WillSleep" to its clients
7850*c54f35caSApple OSS Distributions 					tellChangeUp(fCurrentPowerState);
7851*c54f35caSApple OSS Distributions 				} else {
7852*c54f35caSApple OSS Distributions 					tellNoChangeDown(fHeadNotePowerState);
7853*c54f35caSApple OSS Distributions 				}
7854*c54f35caSApple OSS Distributions 				// mark the change note un-actioned
7855*c54f35caSApple OSS Distributions 				fHeadNoteChangeFlags |= kIOPMNotDone;
7856*c54f35caSApple OSS Distributions 				// and we're done
7857*c54f35caSApple OSS Distributions 				OurChangeFinish();
7858*c54f35caSApple OSS Distributions 			}
7859*c54f35caSApple OSS Distributions 			break;
7860*c54f35caSApple OSS Distributions 
7861*c54f35caSApple OSS Distributions 		case kIOPM_OurChangeTellUserPMPolicyPowerDown:
7862*c54f35caSApple OSS Distributions 			// PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
7863*c54f35caSApple OSS Distributions 			if (fDoNotPowerDown) {
7864*c54f35caSApple OSS Distributions 				OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7865*c54f35caSApple OSS Distributions 				PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7866*c54f35caSApple OSS Distributions 				if (IS_ROOT_DOMAIN) {
7867*c54f35caSApple OSS Distributions 					// RootDomain already sent "WillSleep" to its clients
7868*c54f35caSApple OSS Distributions 					tellChangeUp(fCurrentPowerState);
7869*c54f35caSApple OSS Distributions 				} else {
7870*c54f35caSApple OSS Distributions 					tellNoChangeDown(fHeadNotePowerState);
7871*c54f35caSApple OSS Distributions 				}
7872*c54f35caSApple OSS Distributions 				// mark the change note un-actioned
7873*c54f35caSApple OSS Distributions 				fHeadNoteChangeFlags |= kIOPMNotDone;
7874*c54f35caSApple OSS Distributions 				// and we're done
7875*c54f35caSApple OSS Distributions 				OurChangeFinish();
7876*c54f35caSApple OSS Distributions 			} else {
7877*c54f35caSApple OSS Distributions 				OurChangeTellUserPMPolicyPowerDown();
7878*c54f35caSApple OSS Distributions 			}
7879*c54f35caSApple OSS Distributions 			break;
7880*c54f35caSApple OSS Distributions 
7881*c54f35caSApple OSS Distributions 		case kIOPM_OurChangeTellPriorityClientsPowerDown:
7882*c54f35caSApple OSS Distributions 			// PMRD:     LastCallBeforeSleep notify done
7883*c54f35caSApple OSS Distributions 			// Non-PMRD: tellChangeDown/kNotifyApps done
7884*c54f35caSApple OSS Distributions 			if (fDoNotPowerDown) {
7885*c54f35caSApple OSS Distributions 				OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7886*c54f35caSApple OSS Distributions 				PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
7887*c54f35caSApple OSS Distributions 				// no, tell clients we're back in the old state
7888*c54f35caSApple OSS Distributions 				tellChangeUp(fCurrentPowerState);
7889*c54f35caSApple OSS Distributions 				// mark the change note un-actioned
7890*c54f35caSApple OSS Distributions 				fHeadNoteChangeFlags |= kIOPMNotDone;
7891*c54f35caSApple OSS Distributions 				// and we're done
7892*c54f35caSApple OSS Distributions 				OurChangeFinish();
7893*c54f35caSApple OSS Distributions 			} else {
7894*c54f35caSApple OSS Distributions 				// yes, we can continue
7895*c54f35caSApple OSS Distributions 				OurChangeTellPriorityClientsPowerDown();
7896*c54f35caSApple OSS Distributions 			}
7897*c54f35caSApple OSS Distributions 			break;
7898*c54f35caSApple OSS Distributions 
7899*c54f35caSApple OSS Distributions 		case kIOPM_OurChangeNotifyInterestedDriversWillChange:
7900*c54f35caSApple OSS Distributions 			OurChangeNotifyInterestedDriversWillChange();
7901*c54f35caSApple OSS Distributions 			break;
7902*c54f35caSApple OSS Distributions 
7903*c54f35caSApple OSS Distributions 		case kIOPM_OurChangeSetPowerState:
7904*c54f35caSApple OSS Distributions 			OurChangeSetPowerState();
7905*c54f35caSApple OSS Distributions 			break;
7906*c54f35caSApple OSS Distributions 
7907*c54f35caSApple OSS Distributions 		case kIOPM_OurChangeWaitForPowerSettle:
7908*c54f35caSApple OSS Distributions 			OurChangeWaitForPowerSettle();
7909*c54f35caSApple OSS Distributions 			break;
7910*c54f35caSApple OSS Distributions 
7911*c54f35caSApple OSS Distributions 		case kIOPM_OurChangeNotifyInterestedDriversDidChange:
7912*c54f35caSApple OSS Distributions 			OurChangeNotifyInterestedDriversDidChange();
7913*c54f35caSApple OSS Distributions 			break;
7914*c54f35caSApple OSS Distributions 
7915*c54f35caSApple OSS Distributions 		case kIOPM_OurChangeTellCapabilityDidChange:
7916*c54f35caSApple OSS Distributions 			OurChangeTellCapabilityDidChange();
7917*c54f35caSApple OSS Distributions 			break;
7918*c54f35caSApple OSS Distributions 
7919*c54f35caSApple OSS Distributions 		case kIOPM_OurChangeFinish:
7920*c54f35caSApple OSS Distributions 			OurChangeFinish();
7921*c54f35caSApple OSS Distributions 			break;
7922*c54f35caSApple OSS Distributions 
7923*c54f35caSApple OSS Distributions 		case kIOPM_ParentChangeTellPriorityClientsPowerDown:
7924*c54f35caSApple OSS Distributions 			ParentChangeTellPriorityClientsPowerDown();
7925*c54f35caSApple OSS Distributions 			break;
7926*c54f35caSApple OSS Distributions 
7927*c54f35caSApple OSS Distributions 		case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
7928*c54f35caSApple OSS Distributions 			ParentChangeNotifyInterestedDriversWillChange();
7929*c54f35caSApple OSS Distributions 			break;
7930*c54f35caSApple OSS Distributions 
7931*c54f35caSApple OSS Distributions 		case kIOPM_ParentChangeSetPowerState:
7932*c54f35caSApple OSS Distributions 			ParentChangeSetPowerState();
7933*c54f35caSApple OSS Distributions 			break;
7934*c54f35caSApple OSS Distributions 
7935*c54f35caSApple OSS Distributions 		case kIOPM_ParentChangeWaitForPowerSettle:
7936*c54f35caSApple OSS Distributions 			ParentChangeWaitForPowerSettle();
7937*c54f35caSApple OSS Distributions 			break;
7938*c54f35caSApple OSS Distributions 
7939*c54f35caSApple OSS Distributions 		case kIOPM_ParentChangeNotifyInterestedDriversDidChange:
7940*c54f35caSApple OSS Distributions 			ParentChangeNotifyInterestedDriversDidChange();
7941*c54f35caSApple OSS Distributions 			break;
7942*c54f35caSApple OSS Distributions 
7943*c54f35caSApple OSS Distributions 		case kIOPM_ParentChangeTellCapabilityDidChange:
7944*c54f35caSApple OSS Distributions 			ParentChangeTellCapabilityDidChange();
7945*c54f35caSApple OSS Distributions 			break;
7946*c54f35caSApple OSS Distributions 
7947*c54f35caSApple OSS Distributions 		case kIOPM_ParentChangeAcknowledgePowerChange:
7948*c54f35caSApple OSS Distributions 			ParentChangeAcknowledgePowerChange();
7949*c54f35caSApple OSS Distributions 			break;
7950*c54f35caSApple OSS Distributions 
7951*c54f35caSApple OSS Distributions 		case kIOPM_DriverThreadCallDone:
7952*c54f35caSApple OSS Distributions 			switch (fDriverCallReason) {
7953*c54f35caSApple OSS Distributions 			case kDriverCallInformPreChange:
7954*c54f35caSApple OSS Distributions 			case kDriverCallInformPostChange:
7955*c54f35caSApple OSS Distributions 				notifyInterestedDriversDone();
7956*c54f35caSApple OSS Distributions 				break;
7957*c54f35caSApple OSS Distributions 			case kDriverCallSetPowerState:
7958*c54f35caSApple OSS Distributions 				notifyControllingDriverDone();
7959*c54f35caSApple OSS Distributions 				break;
7960*c54f35caSApple OSS Distributions 			case kRootDomainInformPreChange:
7961*c54f35caSApple OSS Distributions 				notifyRootDomainDone();
7962*c54f35caSApple OSS Distributions 				break;
7963*c54f35caSApple OSS Distributions 			default:
7964*c54f35caSApple OSS Distributions 				panic("%s: bad call reason %x",
7965*c54f35caSApple OSS Distributions 				    getName(), fDriverCallReason);
7966*c54f35caSApple OSS Distributions 			}
7967*c54f35caSApple OSS Distributions 			break;
7968*c54f35caSApple OSS Distributions 
7969*c54f35caSApple OSS Distributions 		case kIOPM_NotifyChildrenOrdered:
7970*c54f35caSApple OSS Distributions 			notifyChildrenOrdered();
7971*c54f35caSApple OSS Distributions 			break;
7972*c54f35caSApple OSS Distributions 
7973*c54f35caSApple OSS Distributions 		case kIOPM_NotifyChildrenDelayed:
7974*c54f35caSApple OSS Distributions 			notifyChildrenDelayed();
7975*c54f35caSApple OSS Distributions 			break;
7976*c54f35caSApple OSS Distributions 
7977*c54f35caSApple OSS Distributions 		case kIOPM_NotifyChildrenStart:
7978*c54f35caSApple OSS Distributions 			// pop notifyAll() state saved by notifyInterestedDriversDone()
7979*c54f35caSApple OSS Distributions 			MS_POP();
7980*c54f35caSApple OSS Distributions 			notifyRootDomain();
7981*c54f35caSApple OSS Distributions 			break;
7982*c54f35caSApple OSS Distributions 
7983*c54f35caSApple OSS Distributions 		case kIOPM_SyncTellClientsPowerDown:
7984*c54f35caSApple OSS Distributions 			// Root domain might self cancel due to assertions.
7985*c54f35caSApple OSS Distributions 			if (IS_ROOT_DOMAIN) {
7986*c54f35caSApple OSS Distributions 				bool cancel = (bool) fDoNotPowerDown;
7987*c54f35caSApple OSS Distributions 				getPMRootDomain()->askChangeDownDone(
7988*c54f35caSApple OSS Distributions 					&fHeadNoteChangeFlags, &cancel);
7989*c54f35caSApple OSS Distributions 				fDoNotPowerDown = cancel;
7990*c54f35caSApple OSS Distributions 			}
7991*c54f35caSApple OSS Distributions 			if (!fDoNotPowerDown) {
7992*c54f35caSApple OSS Distributions 				fMachineState = kIOPM_SyncTellPriorityClientsPowerDown;
7993*c54f35caSApple OSS Distributions 				fOutOfBandParameter = kNotifyApps;
7994*c54f35caSApple OSS Distributions 				tellChangeDown(fHeadNotePowerState);
7995*c54f35caSApple OSS Distributions 			} else {
7996*c54f35caSApple OSS Distributions 				// Cancelled by IOPMrootDomain::askChangeDownDone() or
7997*c54f35caSApple OSS Distributions 				// askChangeDown/kNotifyApps
7998*c54f35caSApple OSS Distributions 				OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7999*c54f35caSApple OSS Distributions 				PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
8000*c54f35caSApple OSS Distributions 				tellNoChangeDown(fHeadNotePowerState);
8001*c54f35caSApple OSS Distributions 				fHeadNoteChangeFlags |= kIOPMNotDone;
8002*c54f35caSApple OSS Distributions 				OurChangeFinish();
8003*c54f35caSApple OSS Distributions 			}
8004*c54f35caSApple OSS Distributions 			break;
8005*c54f35caSApple OSS Distributions 
8006*c54f35caSApple OSS Distributions 		case kIOPM_SyncTellPriorityClientsPowerDown:
8007*c54f35caSApple OSS Distributions 			// PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
8008*c54f35caSApple OSS Distributions 			if (!fDoNotPowerDown) {
8009*c54f35caSApple OSS Distributions 				fMachineState = kIOPM_SyncNotifyWillChange;
8010*c54f35caSApple OSS Distributions 				fOutOfBandParameter = kNotifyPriority;
8011*c54f35caSApple OSS Distributions 				tellChangeDown(fHeadNotePowerState);
8012*c54f35caSApple OSS Distributions 			} else {
8013*c54f35caSApple OSS Distributions 				OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8014*c54f35caSApple OSS Distributions 				PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
8015*c54f35caSApple OSS Distributions 				tellChangeUp(fCurrentPowerState);
8016*c54f35caSApple OSS Distributions 				fHeadNoteChangeFlags |= kIOPMNotDone;
8017*c54f35caSApple OSS Distributions 				OurChangeFinish();
8018*c54f35caSApple OSS Distributions 			}
8019*c54f35caSApple OSS Distributions 			break;
8020*c54f35caSApple OSS Distributions 
8021*c54f35caSApple OSS Distributions 		case kIOPM_SyncNotifyWillChange:
8022*c54f35caSApple OSS Distributions 			if (kIOPMSyncNoChildNotify & fHeadNoteChangeFlags) {
8023*c54f35caSApple OSS Distributions 				fMachineState = kIOPM_SyncFinish;
8024*c54f35caSApple OSS Distributions 				continue;
8025*c54f35caSApple OSS Distributions 			}
8026*c54f35caSApple OSS Distributions 			fMachineState     = kIOPM_SyncNotifyDidChange;
8027*c54f35caSApple OSS Distributions 			fDriverCallReason = kDriverCallInformPreChange;
8028*c54f35caSApple OSS Distributions 			notifyChildren();
8029*c54f35caSApple OSS Distributions 			break;
8030*c54f35caSApple OSS Distributions 
8031*c54f35caSApple OSS Distributions 		case kIOPM_SyncNotifyDidChange:
8032*c54f35caSApple OSS Distributions 			fIsPreChange = false;
8033*c54f35caSApple OSS Distributions 
8034*c54f35caSApple OSS Distributions 			if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
8035*c54f35caSApple OSS Distributions 				fMachineState = kIOPM_SyncFinish;
8036*c54f35caSApple OSS Distributions 			} else {
8037*c54f35caSApple OSS Distributions 				assert(IS_ROOT_DOMAIN);
8038*c54f35caSApple OSS Distributions 				fMachineState = kIOPM_SyncTellCapabilityDidChange;
8039*c54f35caSApple OSS Distributions 			}
8040*c54f35caSApple OSS Distributions 
8041*c54f35caSApple OSS Distributions 			fDriverCallReason = kDriverCallInformPostChange;
8042*c54f35caSApple OSS Distributions 			notifyChildren();
8043*c54f35caSApple OSS Distributions 			break;
8044*c54f35caSApple OSS Distributions 
8045*c54f35caSApple OSS Distributions 		case kIOPM_SyncTellCapabilityDidChange:
8046*c54f35caSApple OSS Distributions 			tellSystemCapabilityChange( kIOPM_SyncFinish );
8047*c54f35caSApple OSS Distributions 			break;
8048*c54f35caSApple OSS Distributions 
8049*c54f35caSApple OSS Distributions 		case kIOPM_SyncFinish:
8050*c54f35caSApple OSS Distributions 			if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
8051*c54f35caSApple OSS Distributions 				ParentChangeAcknowledgePowerChange();
8052*c54f35caSApple OSS Distributions 			} else {
8053*c54f35caSApple OSS Distributions 				OurChangeFinish();
8054*c54f35caSApple OSS Distributions 			}
8055*c54f35caSApple OSS Distributions 			break;
8056*c54f35caSApple OSS Distributions 
8057*c54f35caSApple OSS Distributions 		case kIOPM_TellCapabilityChangeDone:
8058*c54f35caSApple OSS Distributions 			if (fIsPreChange) {
8059*c54f35caSApple OSS Distributions 				if (fOutOfBandParameter == kNotifyCapabilityChangePriority) {
8060*c54f35caSApple OSS Distributions 					MS_POP(); // MS passed to tellSystemCapabilityChange()
8061*c54f35caSApple OSS Distributions 					continue;
8062*c54f35caSApple OSS Distributions 				}
8063*c54f35caSApple OSS Distributions 				fOutOfBandParameter = kNotifyCapabilityChangePriority;
8064*c54f35caSApple OSS Distributions 			} else {
8065*c54f35caSApple OSS Distributions 				if (fOutOfBandParameter == kNotifyCapabilityChangeApps) {
8066*c54f35caSApple OSS Distributions 					MS_POP(); // MS passed to tellSystemCapabilityChange()
8067*c54f35caSApple OSS Distributions 					continue;
8068*c54f35caSApple OSS Distributions 				}
8069*c54f35caSApple OSS Distributions 				fOutOfBandParameter = kNotifyCapabilityChangeApps;
8070*c54f35caSApple OSS Distributions 			}
8071*c54f35caSApple OSS Distributions 			tellClientsWithResponse( fOutOfBandMessage );
8072*c54f35caSApple OSS Distributions 			break;
8073*c54f35caSApple OSS Distributions 
8074*c54f35caSApple OSS Distributions 		default:
8075*c54f35caSApple OSS Distributions 			panic("PMWorkQueueInvoke: unknown machine state %x",
8076*c54f35caSApple OSS Distributions 			    fMachineState);
8077*c54f35caSApple OSS Distributions 		}
8078*c54f35caSApple OSS Distributions 
8079*c54f35caSApple OSS Distributions 		gIOPMRequest = NULL;
8080*c54f35caSApple OSS Distributions 
8081*c54f35caSApple OSS Distributions 		if (fMachineState == kIOPM_Finished) {
8082*c54f35caSApple OSS Distributions 			stop_watchdog_timer();
8083*c54f35caSApple OSS Distributions 			done = true;
8084*c54f35caSApple OSS Distributions 			break;
8085*c54f35caSApple OSS Distributions 		}
8086*c54f35caSApple OSS Distributions 	}
8087*c54f35caSApple OSS Distributions 
8088*c54f35caSApple OSS Distributions 	return done;
8089*c54f35caSApple OSS Distributions }
8090*c54f35caSApple OSS Distributions 
8091*c54f35caSApple OSS Distributions //*********************************************************************************
8092*c54f35caSApple OSS Distributions // [private] executePMRequest
8093*c54f35caSApple OSS Distributions //*********************************************************************************
8094*c54f35caSApple OSS Distributions 
8095*c54f35caSApple OSS Distributions void
executePMRequest(IOPMRequest * request)8096*c54f35caSApple OSS Distributions IOService::executePMRequest( IOPMRequest * request )
8097*c54f35caSApple OSS Distributions {
8098*c54f35caSApple OSS Distributions 	assert( kIOPM_Finished == fMachineState );
8099*c54f35caSApple OSS Distributions 
8100*c54f35caSApple OSS Distributions 	switch (request->getType()) {
8101*c54f35caSApple OSS Distributions 	case kIOPMRequestTypePMStop:
8102*c54f35caSApple OSS Distributions 		handlePMstop( request );
8103*c54f35caSApple OSS Distributions 		break;
8104*c54f35caSApple OSS Distributions 
8105*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeAddPowerChild1:
8106*c54f35caSApple OSS Distributions 		addPowerChild1( request );
8107*c54f35caSApple OSS Distributions 		break;
8108*c54f35caSApple OSS Distributions 
8109*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeAddPowerChild2:
8110*c54f35caSApple OSS Distributions 		addPowerChild2( request );
8111*c54f35caSApple OSS Distributions 		break;
8112*c54f35caSApple OSS Distributions 
8113*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeAddPowerChild3:
8114*c54f35caSApple OSS Distributions 		addPowerChild3( request );
8115*c54f35caSApple OSS Distributions 		break;
8116*c54f35caSApple OSS Distributions 
8117*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeRegisterPowerDriver:
8118*c54f35caSApple OSS Distributions 		handleRegisterPowerDriver( request );
8119*c54f35caSApple OSS Distributions 		break;
8120*c54f35caSApple OSS Distributions 
8121*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeAdjustPowerState:
8122*c54f35caSApple OSS Distributions 		fAdjustPowerScheduled = false;
8123*c54f35caSApple OSS Distributions 		adjustPowerState();
8124*c54f35caSApple OSS Distributions 		break;
8125*c54f35caSApple OSS Distributions 
8126*c54f35caSApple OSS Distributions 	case kIOPMRequestTypePowerDomainWillChange:
8127*c54f35caSApple OSS Distributions 		handlePowerDomainWillChangeTo( request );
8128*c54f35caSApple OSS Distributions 		break;
8129*c54f35caSApple OSS Distributions 
8130*c54f35caSApple OSS Distributions 	case kIOPMRequestTypePowerDomainDidChange:
8131*c54f35caSApple OSS Distributions 		handlePowerDomainDidChangeTo( request );
8132*c54f35caSApple OSS Distributions 		break;
8133*c54f35caSApple OSS Distributions 
8134*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeRequestPowerState:
8135*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeRequestPowerStateOverride:
8136*c54f35caSApple OSS Distributions 		handleRequestPowerState( request );
8137*c54f35caSApple OSS Distributions 		break;
8138*c54f35caSApple OSS Distributions 
8139*c54f35caSApple OSS Distributions 	case kIOPMRequestTypePowerOverrideOnPriv:
8140*c54f35caSApple OSS Distributions 	case kIOPMRequestTypePowerOverrideOffPriv:
8141*c54f35caSApple OSS Distributions 		handlePowerOverrideChanged( request );
8142*c54f35caSApple OSS Distributions 		break;
8143*c54f35caSApple OSS Distributions 
8144*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeActivityTickle:
8145*c54f35caSApple OSS Distributions 		handleActivityTickle( request );
8146*c54f35caSApple OSS Distributions 		break;
8147*c54f35caSApple OSS Distributions 
8148*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeSynchronizePowerTree:
8149*c54f35caSApple OSS Distributions 		handleSynchronizePowerTree( request );
8150*c54f35caSApple OSS Distributions 		break;
8151*c54f35caSApple OSS Distributions 
8152*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeSetIdleTimerPeriod:
8153*c54f35caSApple OSS Distributions 	{
8154*c54f35caSApple OSS Distributions 		fIdleTimerPeriod = (typeof(fIdleTimerPeriod))(uintptr_t) request->fArg0;
8155*c54f35caSApple OSS Distributions 		fNextIdleTimerPeriod = fIdleTimerPeriod;
8156*c54f35caSApple OSS Distributions 		if ((false == fLockedFlags.PMStop) && (fIdleTimerPeriod > 0)) {
8157*c54f35caSApple OSS Distributions 			restartIdleTimer();
8158*c54f35caSApple OSS Distributions 		}
8159*c54f35caSApple OSS Distributions 	}
8160*c54f35caSApple OSS Distributions 	break;
8161*c54f35caSApple OSS Distributions 
8162*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeIgnoreIdleTimer:
8163*c54f35caSApple OSS Distributions 		fIdleTimerIgnored = request->fArg0 ? 1 : 0;
8164*c54f35caSApple OSS Distributions 		break;
8165*c54f35caSApple OSS Distributions 
8166*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeQuiescePowerTree:
8167*c54f35caSApple OSS Distributions 		gIOPMWorkQueue->finishQuiesceRequest(request);
8168*c54f35caSApple OSS Distributions 		break;
8169*c54f35caSApple OSS Distributions 
8170*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeDeferredActivityTickle:
8171*c54f35caSApple OSS Distributions 		handleDeferredActivityTickle(request);
8172*c54f35caSApple OSS Distributions 		break;
8173*c54f35caSApple OSS Distributions 
8174*c54f35caSApple OSS Distributions 	default:
8175*c54f35caSApple OSS Distributions 		panic("executePMRequest: unknown request type %x", request->getType());
8176*c54f35caSApple OSS Distributions 	}
8177*c54f35caSApple OSS Distributions }
8178*c54f35caSApple OSS Distributions 
8179*c54f35caSApple OSS Distributions //*********************************************************************************
8180*c54f35caSApple OSS Distributions // [private] actionPMReplyQueue
8181*c54f35caSApple OSS Distributions //
8182*c54f35caSApple OSS Distributions // IOPMRequestQueue::checkForWork() passing a reply-type request to the
8183*c54f35caSApple OSS Distributions // request target.
8184*c54f35caSApple OSS Distributions //*********************************************************************************
8185*c54f35caSApple OSS Distributions 
8186*c54f35caSApple OSS Distributions bool
actionPMReplyQueue(IOPMRequest * request,IOPMRequestQueue * queue)8187*c54f35caSApple OSS Distributions IOService::actionPMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
8188*c54f35caSApple OSS Distributions {
8189*c54f35caSApple OSS Distributions 	bool more = false;
8190*c54f35caSApple OSS Distributions 
8191*c54f35caSApple OSS Distributions 	assert( request && queue );
8192*c54f35caSApple OSS Distributions 	assert( request->isReplyType());
8193*c54f35caSApple OSS Distributions 
8194*c54f35caSApple OSS Distributions 	PM_LOG1("[A %02x] %p [%p %s] state %d\n",
8195*c54f35caSApple OSS Distributions 	    request->getType(), OBFUSCATE(request),
8196*c54f35caSApple OSS Distributions 	    OBFUSCATE(this), getName(), fMachineState);
8197*c54f35caSApple OSS Distributions 
8198*c54f35caSApple OSS Distributions 	switch (request->getType()) {
8199*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeAllowPowerChange:
8200*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeCancelPowerChange:
8201*c54f35caSApple OSS Distributions 		// Check if we are expecting this response.
8202*c54f35caSApple OSS Distributions 		if (responseValid((uint32_t)(uintptr_t) request->fArg0,
8203*c54f35caSApple OSS Distributions 		    (int)(uintptr_t) request->fArg1)) {
8204*c54f35caSApple OSS Distributions 			if (kIOPMRequestTypeCancelPowerChange == request->getType()) {
8205*c54f35caSApple OSS Distributions 				// Clients are not allowed to cancel when kIOPMSkipAskPowerDown
8206*c54f35caSApple OSS Distributions 				// flag is set. Only root domain will set this flag.
8207*c54f35caSApple OSS Distributions 				// However, there is one exception to this rule. User-space PM
8208*c54f35caSApple OSS Distributions 				// policy may choose to cancel sleep even after all clients have
8209*c54f35caSApple OSS Distributions 				// been notified that we will lower power.
8210*c54f35caSApple OSS Distributions 
8211*c54f35caSApple OSS Distributions 				if ((fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
8212*c54f35caSApple OSS Distributions 				    || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
8213*c54f35caSApple OSS Distributions 				    || ((fHeadNoteChangeFlags & kIOPMSkipAskPowerDown) == 0)) {
8214*c54f35caSApple OSS Distributions 					fDoNotPowerDown = true;
8215*c54f35caSApple OSS Distributions 
8216*c54f35caSApple OSS Distributions 					OSString * name = (OSString *) request->fArg2;
8217*c54f35caSApple OSS Distributions 					getPMRootDomain()->pmStatsRecordApplicationResponse(
8218*c54f35caSApple OSS Distributions 						gIOPMStatsResponseCancel,
8219*c54f35caSApple OSS Distributions 						name ? name->getCStringNoCopy() : "", 0,
8220*c54f35caSApple OSS Distributions 						0, (int)(uintptr_t) request->fArg1, NULL);
8221*c54f35caSApple OSS Distributions 				}
8222*c54f35caSApple OSS Distributions 			}
8223*c54f35caSApple OSS Distributions 
8224*c54f35caSApple OSS Distributions 			if (checkForDone()) {
8225*c54f35caSApple OSS Distributions 				stop_ack_timer();
8226*c54f35caSApple OSS Distributions 				cleanClientResponses(false);
8227*c54f35caSApple OSS Distributions 				more = true;
8228*c54f35caSApple OSS Distributions 			}
8229*c54f35caSApple OSS Distributions 		}
8230*c54f35caSApple OSS Distributions 		// OSString containing app name in Arg2 must be released.
8231*c54f35caSApple OSS Distributions 		if (request->getType() == kIOPMRequestTypeCancelPowerChange) {
8232*c54f35caSApple OSS Distributions 			OSObject * obj = (OSObject *) request->fArg2;
8233*c54f35caSApple OSS Distributions 			if (obj) {
8234*c54f35caSApple OSS Distributions 				obj->release();
8235*c54f35caSApple OSS Distributions 			}
8236*c54f35caSApple OSS Distributions 		}
8237*c54f35caSApple OSS Distributions 		break;
8238*c54f35caSApple OSS Distributions 
8239*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeAckPowerChange:
8240*c54f35caSApple OSS Distributions 		more = handleAcknowledgePowerChange( request );
8241*c54f35caSApple OSS Distributions 		break;
8242*c54f35caSApple OSS Distributions 
8243*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeAckSetPowerState:
8244*c54f35caSApple OSS Distributions 		more = handleAcknowledgeSetPowerState( request );
8245*c54f35caSApple OSS Distributions 		break;
8246*c54f35caSApple OSS Distributions 
8247*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeInterestChanged:
8248*c54f35caSApple OSS Distributions 		handleInterestChanged( request );
8249*c54f35caSApple OSS Distributions 		more = true;
8250*c54f35caSApple OSS Distributions 		break;
8251*c54f35caSApple OSS Distributions 
8252*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeIdleCancel:
8253*c54f35caSApple OSS Distributions 		if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown)
8254*c54f35caSApple OSS Distributions 		    || (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
8255*c54f35caSApple OSS Distributions 		    || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
8256*c54f35caSApple OSS Distributions 		    || (fMachineState == kIOPM_SyncTellClientsPowerDown)
8257*c54f35caSApple OSS Distributions 		    || (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown)) {
8258*c54f35caSApple OSS Distributions 			OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8259*c54f35caSApple OSS Distributions 			PM_LOG2("%s: cancel from machine state %d\n",
8260*c54f35caSApple OSS Distributions 			    getName(), fMachineState);
8261*c54f35caSApple OSS Distributions 			fDoNotPowerDown = true;
8262*c54f35caSApple OSS Distributions 			// Stop waiting for app replys.
8263*c54f35caSApple OSS Distributions 			if ((fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown) ||
8264*c54f35caSApple OSS Distributions 			    (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown) ||
8265*c54f35caSApple OSS Distributions 			    (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown) ||
8266*c54f35caSApple OSS Distributions 			    (fMachineState == kIOPM_SyncTellClientsPowerDown)) {
8267*c54f35caSApple OSS Distributions 				cleanClientResponses(false);
8268*c54f35caSApple OSS Distributions 			}
8269*c54f35caSApple OSS Distributions 			more = true;
8270*c54f35caSApple OSS Distributions 		}
8271*c54f35caSApple OSS Distributions 		break;
8272*c54f35caSApple OSS Distributions 
8273*c54f35caSApple OSS Distributions 	case kIOPMRequestTypeChildNotifyDelayCancel:
8274*c54f35caSApple OSS Distributions 		if (fMachineState == kIOPM_NotifyChildrenDelayed) {
8275*c54f35caSApple OSS Distributions 			PM_LOG2("%s: delay notify cancelled\n", getName());
8276*c54f35caSApple OSS Distributions 			notifyChildrenDelayed();
8277*c54f35caSApple OSS Distributions 		}
8278*c54f35caSApple OSS Distributions 		break;
8279*c54f35caSApple OSS Distributions 
8280*c54f35caSApple OSS Distributions 	default:
8281*c54f35caSApple OSS Distributions 		panic("PMReplyQueue: unknown reply type %x", request->getType());
8282*c54f35caSApple OSS Distributions 	}
8283*c54f35caSApple OSS Distributions 
8284*c54f35caSApple OSS Distributions 	more |= gIOPMCompletionQueue->queuePMRequest(request);
8285*c54f35caSApple OSS Distributions 	if (more) {
8286*c54f35caSApple OSS Distributions 		gIOPMWorkQueue->incrementProducerCount();
8287*c54f35caSApple OSS Distributions 	}
8288*c54f35caSApple OSS Distributions 
8289*c54f35caSApple OSS Distributions 	return more;
8290*c54f35caSApple OSS Distributions }
8291*c54f35caSApple OSS Distributions 
8292*c54f35caSApple OSS Distributions //*********************************************************************************
8293*c54f35caSApple OSS Distributions // [private] assertPMDriverCall / deassertPMDriverCall
8294*c54f35caSApple OSS Distributions //*********************************************************************************
8295*c54f35caSApple OSS Distributions 
8296*c54f35caSApple OSS Distributions bool
assertPMDriverCall(IOPMDriverCallEntry * entry,IOOptionBits method,const IOPMinformee * inform,IOOptionBits options)8297*c54f35caSApple OSS Distributions IOService::assertPMDriverCall(
8298*c54f35caSApple OSS Distributions 	IOPMDriverCallEntry *   entry,
8299*c54f35caSApple OSS Distributions 	IOOptionBits            method,
8300*c54f35caSApple OSS Distributions 	const IOPMinformee *    inform,
8301*c54f35caSApple OSS Distributions 	IOOptionBits            options )
8302*c54f35caSApple OSS Distributions {
8303*c54f35caSApple OSS Distributions 	IOService * target = NULL;
8304*c54f35caSApple OSS Distributions 	bool        ok = false;
8305*c54f35caSApple OSS Distributions 
8306*c54f35caSApple OSS Distributions 	if (!initialized) {
8307*c54f35caSApple OSS Distributions 		return false;
8308*c54f35caSApple OSS Distributions 	}
8309*c54f35caSApple OSS Distributions 
8310*c54f35caSApple OSS Distributions 	PM_LOCK();
8311*c54f35caSApple OSS Distributions 
8312*c54f35caSApple OSS Distributions 	if (fLockedFlags.PMStop) {
8313*c54f35caSApple OSS Distributions 		goto fail;
8314*c54f35caSApple OSS Distributions 	}
8315*c54f35caSApple OSS Distributions 
8316*c54f35caSApple OSS Distributions 	if (((options & kIOPMDriverCallNoInactiveCheck) == 0) && isInactive()) {
8317*c54f35caSApple OSS Distributions 		goto fail;
8318*c54f35caSApple OSS Distributions 	}
8319*c54f35caSApple OSS Distributions 
8320*c54f35caSApple OSS Distributions 	if (inform) {
8321*c54f35caSApple OSS Distributions 		if (!inform->active) {
8322*c54f35caSApple OSS Distributions 			goto fail;
8323*c54f35caSApple OSS Distributions 		}
8324*c54f35caSApple OSS Distributions 		target = inform->whatObject;
8325*c54f35caSApple OSS Distributions 		if (target->isInactive()) {
8326*c54f35caSApple OSS Distributions 			goto fail;
8327*c54f35caSApple OSS Distributions 		}
8328*c54f35caSApple OSS Distributions 	}
8329*c54f35caSApple OSS Distributions 
8330*c54f35caSApple OSS Distributions 	// Record calling address for sleep failure diagnostics
8331*c54f35caSApple OSS Distributions 	switch (method) {
8332*c54f35caSApple OSS Distributions 	case kIOPMDriverCallMethodSetPowerState:
8333*c54f35caSApple OSS Distributions 		entry->callMethod = OSMemberFunctionCast(const void *, fControllingDriver, &IOService::setPowerState);
8334*c54f35caSApple OSS Distributions 		break;
8335*c54f35caSApple OSS Distributions 	case kIOPMDriverCallMethodWillChange:
8336*c54f35caSApple OSS Distributions 		entry->callMethod = OSMemberFunctionCast(const void *, target, &IOService::powerStateWillChangeTo);
8337*c54f35caSApple OSS Distributions 		break;
8338*c54f35caSApple OSS Distributions 	case kIOPMDriverCallMethodDidChange:
8339*c54f35caSApple OSS Distributions 		entry->callMethod = OSMemberFunctionCast(const void *, target, &IOService::powerStateDidChangeTo);
8340*c54f35caSApple OSS Distributions 		break;
8341*c54f35caSApple OSS Distributions 	case kIOPMDriverCallMethodUnknown:
8342*c54f35caSApple OSS Distributions 	case kIOPMDriverCallMethodSetAggressive:
8343*c54f35caSApple OSS Distributions 	default:
8344*c54f35caSApple OSS Distributions 		entry->callMethod = NULL;
8345*c54f35caSApple OSS Distributions 		break;
8346*c54f35caSApple OSS Distributions 	}
8347*c54f35caSApple OSS Distributions 
8348*c54f35caSApple OSS Distributions 	entry->thread = current_thread();
8349*c54f35caSApple OSS Distributions 	entry->target = target;
8350*c54f35caSApple OSS Distributions 	queue_enter(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
8351*c54f35caSApple OSS Distributions 	ok = true;
8352*c54f35caSApple OSS Distributions 
8353*c54f35caSApple OSS Distributions fail:
8354*c54f35caSApple OSS Distributions 	PM_UNLOCK();
8355*c54f35caSApple OSS Distributions 
8356*c54f35caSApple OSS Distributions 	return ok;
8357*c54f35caSApple OSS Distributions }
8358*c54f35caSApple OSS Distributions 
8359*c54f35caSApple OSS Distributions void
deassertPMDriverCall(IOPMDriverCallEntry * entry)8360*c54f35caSApple OSS Distributions IOService::deassertPMDriverCall( IOPMDriverCallEntry * entry )
8361*c54f35caSApple OSS Distributions {
8362*c54f35caSApple OSS Distributions 	bool wakeup = false;
8363*c54f35caSApple OSS Distributions 
8364*c54f35caSApple OSS Distributions 	PM_LOCK();
8365*c54f35caSApple OSS Distributions 
8366*c54f35caSApple OSS Distributions 	assert( !queue_empty(&fPMDriverCallQueue));
8367*c54f35caSApple OSS Distributions 	queue_remove(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
8368*c54f35caSApple OSS Distributions 	if (fLockedFlags.PMDriverCallWait) {
8369*c54f35caSApple OSS Distributions 		wakeup = true;
8370*c54f35caSApple OSS Distributions 	}
8371*c54f35caSApple OSS Distributions 
8372*c54f35caSApple OSS Distributions 	PM_UNLOCK();
8373*c54f35caSApple OSS Distributions 
8374*c54f35caSApple OSS Distributions 	if (wakeup) {
8375*c54f35caSApple OSS Distributions 		PM_LOCK_WAKEUP(&fPMDriverCallQueue);
8376*c54f35caSApple OSS Distributions 	}
8377*c54f35caSApple OSS Distributions }
8378*c54f35caSApple OSS Distributions 
8379*c54f35caSApple OSS Distributions bool
getBlockingDriverCall(thread_t * thread,const void ** callMethod)8380*c54f35caSApple OSS Distributions IOService::getBlockingDriverCall(thread_t *thread, const void **callMethod)
8381*c54f35caSApple OSS Distributions {
8382*c54f35caSApple OSS Distributions 	const IOPMDriverCallEntry * entry = NULL;
8383*c54f35caSApple OSS Distributions 	bool    blocked = false;
8384*c54f35caSApple OSS Distributions 
8385*c54f35caSApple OSS Distributions 	if (!initialized) {
8386*c54f35caSApple OSS Distributions 		return false;
8387*c54f35caSApple OSS Distributions 	}
8388*c54f35caSApple OSS Distributions 
8389*c54f35caSApple OSS Distributions 	if (current_thread() != gIOPMWatchDogThread) {
8390*c54f35caSApple OSS Distributions 		// Meant to be accessed only from watchdog thread
8391*c54f35caSApple OSS Distributions 		return false;
8392*c54f35caSApple OSS Distributions 	}
8393*c54f35caSApple OSS Distributions 
8394*c54f35caSApple OSS Distributions 	PM_LOCK();
8395*c54f35caSApple OSS Distributions 	entry = qe_queue_first(&fPMDriverCallQueue, IOPMDriverCallEntry, link);
8396*c54f35caSApple OSS Distributions 	if (entry) {
8397*c54f35caSApple OSS Distributions 		*thread = entry->thread;
8398*c54f35caSApple OSS Distributions 		*callMethod = entry->callMethod;
8399*c54f35caSApple OSS Distributions 		blocked = true;
8400*c54f35caSApple OSS Distributions 	}
8401*c54f35caSApple OSS Distributions 	PM_UNLOCK();
8402*c54f35caSApple OSS Distributions 
8403*c54f35caSApple OSS Distributions 	return blocked;
8404*c54f35caSApple OSS Distributions }
8405*c54f35caSApple OSS Distributions 
8406*c54f35caSApple OSS Distributions 
8407*c54f35caSApple OSS Distributions void
waitForPMDriverCall(IOService * target)8408*c54f35caSApple OSS Distributions IOService::waitForPMDriverCall( IOService * target )
8409*c54f35caSApple OSS Distributions {
8410*c54f35caSApple OSS Distributions 	const IOPMDriverCallEntry * entry;
8411*c54f35caSApple OSS Distributions 	thread_t                    thread = current_thread();
8412*c54f35caSApple OSS Distributions 	AbsoluteTime                deadline;
8413*c54f35caSApple OSS Distributions 	int                         waitResult;
8414*c54f35caSApple OSS Distributions 	bool                        log = true;
8415*c54f35caSApple OSS Distributions 	bool                        wait;
8416*c54f35caSApple OSS Distributions 
8417*c54f35caSApple OSS Distributions 	do {
8418*c54f35caSApple OSS Distributions 		wait = false;
8419*c54f35caSApple OSS Distributions 		queue_iterate(&fPMDriverCallQueue, entry, const IOPMDriverCallEntry *, link)
8420*c54f35caSApple OSS Distributions 		{
8421*c54f35caSApple OSS Distributions 			// Target of interested driver call
8422*c54f35caSApple OSS Distributions 			if (target && (target != entry->target)) {
8423*c54f35caSApple OSS Distributions 				continue;
8424*c54f35caSApple OSS Distributions 			}
8425*c54f35caSApple OSS Distributions 
8426*c54f35caSApple OSS Distributions 			if (entry->thread == thread) {
8427*c54f35caSApple OSS Distributions 				if (log) {
8428*c54f35caSApple OSS Distributions 					PM_LOG("%s: %s(%s) on PM thread\n",
8429*c54f35caSApple OSS Distributions 					    fName, __FUNCTION__, target ? target->getName() : "");
8430*c54f35caSApple OSS Distributions 					OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
8431*c54f35caSApple OSS Distributions 					    fName, __FUNCTION__, target ? target->getName() : "");
8432*c54f35caSApple OSS Distributions 					log = false;
8433*c54f35caSApple OSS Distributions 				}
8434*c54f35caSApple OSS Distributions 				continue;
8435*c54f35caSApple OSS Distributions 			}
8436*c54f35caSApple OSS Distributions 
8437*c54f35caSApple OSS Distributions 			wait = true;
8438*c54f35caSApple OSS Distributions 			break;
8439*c54f35caSApple OSS Distributions 		}
8440*c54f35caSApple OSS Distributions 
8441*c54f35caSApple OSS Distributions 		if (wait) {
8442*c54f35caSApple OSS Distributions 			fLockedFlags.PMDriverCallWait = true;
8443*c54f35caSApple OSS Distributions 			clock_interval_to_deadline(15, kSecondScale, &deadline);
8444*c54f35caSApple OSS Distributions 			waitResult = PM_LOCK_SLEEP(&fPMDriverCallQueue, deadline);
8445*c54f35caSApple OSS Distributions 			fLockedFlags.PMDriverCallWait = false;
8446*c54f35caSApple OSS Distributions 			if (THREAD_TIMED_OUT == waitResult) {
8447*c54f35caSApple OSS Distributions 				PM_ERROR("%s: waitForPMDriverCall timeout\n", fName);
8448*c54f35caSApple OSS Distributions 				wait = false;
8449*c54f35caSApple OSS Distributions 			}
8450*c54f35caSApple OSS Distributions 		}
8451*c54f35caSApple OSS Distributions 	} while (wait);
8452*c54f35caSApple OSS Distributions }
8453*c54f35caSApple OSS Distributions 
8454*c54f35caSApple OSS Distributions //*********************************************************************************
8455*c54f35caSApple OSS Distributions // [private] Debug helpers
8456*c54f35caSApple OSS Distributions //*********************************************************************************
8457*c54f35caSApple OSS Distributions 
8458*c54f35caSApple OSS Distributions const char *
getIOMessageString(uint32_t msg)8459*c54f35caSApple OSS Distributions IOService::getIOMessageString( uint32_t msg )
8460*c54f35caSApple OSS Distributions {
8461*c54f35caSApple OSS Distributions #define MSG_ENTRY(x)    {(int) x, #x}
8462*c54f35caSApple OSS Distributions 
8463*c54f35caSApple OSS Distributions 	static const IONamedValue msgNames[] = {
8464*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageCanDevicePowerOff      ),
8465*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageDeviceWillPowerOff     ),
8466*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageDeviceWillNotPowerOff  ),
8467*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageDeviceHasPoweredOn     ),
8468*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageCanSystemPowerOff      ),
8469*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemWillPowerOff     ),
8470*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemWillNotPowerOff  ),
8471*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageCanSystemSleep         ),
8472*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemWillSleep        ),
8473*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemWillNotSleep     ),
8474*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemHasPoweredOn     ),
8475*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemWillRestart      ),
8476*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemWillPowerOn      ),
8477*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemCapabilityChange ),
8478*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOPMMessageLastCallBeforeSleep  ),
8479*c54f35caSApple OSS Distributions 		MSG_ENTRY( kIOMessageSystemPagingOff        ),
8480*c54f35caSApple OSS Distributions 		{ 0, NULL }
8481*c54f35caSApple OSS Distributions 	};
8482*c54f35caSApple OSS Distributions 
8483*c54f35caSApple OSS Distributions 	return IOFindNameForValue(msg, msgNames);
8484*c54f35caSApple OSS Distributions }
8485*c54f35caSApple OSS Distributions 
8486*c54f35caSApple OSS Distributions static const char *
getNotificationPhaseString(uint32_t phase)8487*c54f35caSApple OSS Distributions getNotificationPhaseString( uint32_t phase )
8488*c54f35caSApple OSS Distributions {
8489*c54f35caSApple OSS Distributions #define PHASE_ENTRY(x)    {(int) x, #x}
8490*c54f35caSApple OSS Distributions 
8491*c54f35caSApple OSS Distributions 	static const IONamedValue phaseNames[] = {
8492*c54f35caSApple OSS Distributions 		PHASE_ENTRY( kNotifyApps                     ),
8493*c54f35caSApple OSS Distributions 		PHASE_ENTRY( kNotifyPriority                 ),
8494*c54f35caSApple OSS Distributions 		PHASE_ENTRY( kNotifyCapabilityChangeApps     ),
8495*c54f35caSApple OSS Distributions 		PHASE_ENTRY( kNotifyCapabilityChangePriority ),
8496*c54f35caSApple OSS Distributions 		{ 0, NULL }
8497*c54f35caSApple OSS Distributions 	};
8498*c54f35caSApple OSS Distributions 
8499*c54f35caSApple OSS Distributions 	return IOFindNameForValue(phase, phaseNames);
8500*c54f35caSApple OSS Distributions }
8501*c54f35caSApple OSS Distributions 
8502*c54f35caSApple OSS Distributions // MARK: -
8503*c54f35caSApple OSS Distributions // MARK: IOPMRequest
8504*c54f35caSApple OSS Distributions 
8505*c54f35caSApple OSS Distributions //*********************************************************************************
8506*c54f35caSApple OSS Distributions // IOPMRequest Class
8507*c54f35caSApple OSS Distributions //
8508*c54f35caSApple OSS Distributions // Requests from PM clients, and also used for inter-object messaging within PM.
8509*c54f35caSApple OSS Distributions //*********************************************************************************
8510*c54f35caSApple OSS Distributions 
8511*c54f35caSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
8512*c54f35caSApple OSS Distributions 
8513*c54f35caSApple OSS Distributions IOPMRequest *
create(void)8514*c54f35caSApple OSS Distributions IOPMRequest::create( void )
8515*c54f35caSApple OSS Distributions {
8516*c54f35caSApple OSS Distributions 	IOPMRequest * me = OSTypeAlloc(IOPMRequest);
8517*c54f35caSApple OSS Distributions 	if (me && !me->init(NULL, kIOPMRequestTypeInvalid)) {
8518*c54f35caSApple OSS Distributions 		me->release();
8519*c54f35caSApple OSS Distributions 		me = NULL;
8520*c54f35caSApple OSS Distributions 	}
8521*c54f35caSApple OSS Distributions 	return me;
8522*c54f35caSApple OSS Distributions }
8523*c54f35caSApple OSS Distributions 
8524*c54f35caSApple OSS Distributions bool
init(IOService * target,IOOptionBits type)8525*c54f35caSApple OSS Distributions IOPMRequest::init( IOService * target, IOOptionBits type )
8526*c54f35caSApple OSS Distributions {
8527*c54f35caSApple OSS Distributions 	if (!IOCommand::init()) {
8528*c54f35caSApple OSS Distributions 		return false;
8529*c54f35caSApple OSS Distributions 	}
8530*c54f35caSApple OSS Distributions 
8531*c54f35caSApple OSS Distributions 	fRequestType = type;
8532*c54f35caSApple OSS Distributions 	fTarget = target;
8533*c54f35caSApple OSS Distributions 
8534*c54f35caSApple OSS Distributions 	if (fTarget) {
8535*c54f35caSApple OSS Distributions 		fTarget->retain();
8536*c54f35caSApple OSS Distributions 	}
8537*c54f35caSApple OSS Distributions 
8538*c54f35caSApple OSS Distributions 	// Root node and root domain requests does not prevent the power tree from
8539*c54f35caSApple OSS Distributions 	// becoming quiescent.
8540*c54f35caSApple OSS Distributions 
8541*c54f35caSApple OSS Distributions 	fIsQuiesceBlocker = ((fTarget != gIOPMRootNode) &&
8542*c54f35caSApple OSS Distributions 	    (fTarget != IOService::getPMRootDomain()));
8543*c54f35caSApple OSS Distributions 
8544*c54f35caSApple OSS Distributions 	return true;
8545*c54f35caSApple OSS Distributions }
8546*c54f35caSApple OSS Distributions 
8547*c54f35caSApple OSS Distributions void
reset(void)8548*c54f35caSApple OSS Distributions IOPMRequest::reset( void )
8549*c54f35caSApple OSS Distributions {
8550*c54f35caSApple OSS Distributions 	assert( fWorkWaitCount == 0 );
8551*c54f35caSApple OSS Distributions 	assert( fFreeWaitCount == 0 );
8552*c54f35caSApple OSS Distributions 
8553*c54f35caSApple OSS Distributions 	detachNextRequest();
8554*c54f35caSApple OSS Distributions 	detachRootRequest();
8555*c54f35caSApple OSS Distributions 
8556*c54f35caSApple OSS Distributions 	if (fCompletionAction && (fRequestType == kIOPMRequestTypeQuiescePowerTree)) {
8557*c54f35caSApple OSS Distributions 		// Call the completion on PM work loop context
8558*c54f35caSApple OSS Distributions 		fCompletionAction(fCompletionTarget, fCompletionParam);
8559*c54f35caSApple OSS Distributions 		fCompletionAction = NULL;
8560*c54f35caSApple OSS Distributions 	}
8561*c54f35caSApple OSS Distributions 
8562*c54f35caSApple OSS Distributions 	fRequestType = kIOPMRequestTypeInvalid;
8563*c54f35caSApple OSS Distributions 
8564*c54f35caSApple OSS Distributions 	if (fTarget) {
8565*c54f35caSApple OSS Distributions 		fTarget->release();
8566*c54f35caSApple OSS Distributions 		fTarget = NULL;
8567*c54f35caSApple OSS Distributions 	}
8568*c54f35caSApple OSS Distributions }
8569*c54f35caSApple OSS Distributions 
8570*c54f35caSApple OSS Distributions bool
attachNextRequest(IOPMRequest * next)8571*c54f35caSApple OSS Distributions IOPMRequest::attachNextRequest( IOPMRequest * next )
8572*c54f35caSApple OSS Distributions {
8573*c54f35caSApple OSS Distributions 	bool ok = false;
8574*c54f35caSApple OSS Distributions 
8575*c54f35caSApple OSS Distributions 	if (!fRequestNext) {
8576*c54f35caSApple OSS Distributions 		// Postpone the execution of the next request after
8577*c54f35caSApple OSS Distributions 		// this request.
8578*c54f35caSApple OSS Distributions 		fRequestNext = next;
8579*c54f35caSApple OSS Distributions 		fRequestNext->fWorkWaitCount++;
8580*c54f35caSApple OSS Distributions #if LOG_REQUEST_ATTACH
8581*c54f35caSApple OSS Distributions 		PM_LOG("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
8582*c54f35caSApple OSS Distributions 		    OBFUSCATE(this), fRequestType, OBFUSCATE(fRequestNext),
8583*c54f35caSApple OSS Distributions 		    fRequestNext->fRequestType,
8584*c54f35caSApple OSS Distributions 		    (uint32_t) fRequestNext->fWorkWaitCount,
8585*c54f35caSApple OSS Distributions 		    fTarget->getName());
8586*c54f35caSApple OSS Distributions #endif
8587*c54f35caSApple OSS Distributions 		ok = true;
8588*c54f35caSApple OSS Distributions 	}
8589*c54f35caSApple OSS Distributions 	return ok;
8590*c54f35caSApple OSS Distributions }
8591*c54f35caSApple OSS Distributions 
8592*c54f35caSApple OSS Distributions bool
detachNextRequest(void)8593*c54f35caSApple OSS Distributions IOPMRequest::detachNextRequest( void )
8594*c54f35caSApple OSS Distributions {
8595*c54f35caSApple OSS Distributions 	bool ok = false;
8596*c54f35caSApple OSS Distributions 
8597*c54f35caSApple OSS Distributions 	if (fRequestNext) {
8598*c54f35caSApple OSS Distributions 		assert(fRequestNext->fWorkWaitCount);
8599*c54f35caSApple OSS Distributions 		if (fRequestNext->fWorkWaitCount) {
8600*c54f35caSApple OSS Distributions 			fRequestNext->fWorkWaitCount--;
8601*c54f35caSApple OSS Distributions 		}
8602*c54f35caSApple OSS Distributions #if LOG_REQUEST_ATTACH
8603*c54f35caSApple OSS Distributions 		PM_LOG("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
8604*c54f35caSApple OSS Distributions 		    OBFUSCATE(this), fRequestType, OBFUSCATE(fRequestNext),
8605*c54f35caSApple OSS Distributions 		    fRequestNext->fRequestType,
8606*c54f35caSApple OSS Distributions 		    (uint32_t) fRequestNext->fWorkWaitCount,
8607*c54f35caSApple OSS Distributions 		    fTarget->getName());
8608*c54f35caSApple OSS Distributions #endif
8609*c54f35caSApple OSS Distributions 		fRequestNext = NULL;
8610*c54f35caSApple OSS Distributions 		ok = true;
8611*c54f35caSApple OSS Distributions 	}
8612*c54f35caSApple OSS Distributions 	return ok;
8613*c54f35caSApple OSS Distributions }
8614*c54f35caSApple OSS Distributions 
8615*c54f35caSApple OSS Distributions bool
attachRootRequest(IOPMRequest * root)8616*c54f35caSApple OSS Distributions IOPMRequest::attachRootRequest( IOPMRequest * root )
8617*c54f35caSApple OSS Distributions {
8618*c54f35caSApple OSS Distributions 	bool ok = false;
8619*c54f35caSApple OSS Distributions 
8620*c54f35caSApple OSS Distributions 	if (!fRequestRoot) {
8621*c54f35caSApple OSS Distributions 		// Delay the completion of the root request after
8622*c54f35caSApple OSS Distributions 		// this request.
8623*c54f35caSApple OSS Distributions 		fRequestRoot = root;
8624*c54f35caSApple OSS Distributions 		fRequestRoot->fFreeWaitCount++;
8625*c54f35caSApple OSS Distributions #if LOG_REQUEST_ATTACH
8626*c54f35caSApple OSS Distributions 		PM_LOG("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
8627*c54f35caSApple OSS Distributions 		    OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
8628*c54f35caSApple OSS Distributions 		    (uint32_t) fRequestRoot->fType,
8629*c54f35caSApple OSS Distributions 		    (uint32_t) fRequestRoot->fFreeWaitCount,
8630*c54f35caSApple OSS Distributions 		    fTarget->getName());
8631*c54f35caSApple OSS Distributions #endif
8632*c54f35caSApple OSS Distributions 		ok = true;
8633*c54f35caSApple OSS Distributions 	}
8634*c54f35caSApple OSS Distributions 	return ok;
8635*c54f35caSApple OSS Distributions }
8636*c54f35caSApple OSS Distributions 
8637*c54f35caSApple OSS Distributions bool
detachRootRequest(void)8638*c54f35caSApple OSS Distributions IOPMRequest::detachRootRequest( void )
8639*c54f35caSApple OSS Distributions {
8640*c54f35caSApple OSS Distributions 	bool ok = false;
8641*c54f35caSApple OSS Distributions 
8642*c54f35caSApple OSS Distributions 	if (fRequestRoot) {
8643*c54f35caSApple OSS Distributions 		assert(fRequestRoot->fFreeWaitCount);
8644*c54f35caSApple OSS Distributions 		if (fRequestRoot->fFreeWaitCount) {
8645*c54f35caSApple OSS Distributions 			fRequestRoot->fFreeWaitCount--;
8646*c54f35caSApple OSS Distributions 		}
8647*c54f35caSApple OSS Distributions #if LOG_REQUEST_ATTACH
8648*c54f35caSApple OSS Distributions 		PM_LOG("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
8649*c54f35caSApple OSS Distributions 		    OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
8650*c54f35caSApple OSS Distributions 		    (uint32_t) fRequestRoot->fType,
8651*c54f35caSApple OSS Distributions 		    (uint32_t) fRequestRoot->fFreeWaitCount,
8652*c54f35caSApple OSS Distributions 		    fTarget->getName());
8653*c54f35caSApple OSS Distributions #endif
8654*c54f35caSApple OSS Distributions 		fRequestRoot = NULL;
8655*c54f35caSApple OSS Distributions 		ok = true;
8656*c54f35caSApple OSS Distributions 	}
8657*c54f35caSApple OSS Distributions 	return ok;
8658*c54f35caSApple OSS Distributions }
8659*c54f35caSApple OSS Distributions 
8660*c54f35caSApple OSS Distributions // MARK: -
8661*c54f35caSApple OSS Distributions // MARK: IOPMRequestQueue
8662*c54f35caSApple OSS Distributions 
8663*c54f35caSApple OSS Distributions //*********************************************************************************
8664*c54f35caSApple OSS Distributions // IOPMRequestQueue Class
8665*c54f35caSApple OSS Distributions //
8666*c54f35caSApple OSS Distributions // Global queues. Queues are created once and never released.
8667*c54f35caSApple OSS Distributions //*********************************************************************************
8668*c54f35caSApple OSS Distributions 
8669*c54f35caSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
8670*c54f35caSApple OSS Distributions 
8671*c54f35caSApple OSS Distributions #pragma clang diagnostic push
8672*c54f35caSApple OSS Distributions #pragma clang diagnostic ignored "-Wcast-function-type"
8673*c54f35caSApple OSS Distributions 
8674*c54f35caSApple OSS Distributions IOPMRequestQueue *
create(IOService * inOwner,Action inAction)8675*c54f35caSApple OSS Distributions IOPMRequestQueue::create( IOService * inOwner, Action inAction )
8676*c54f35caSApple OSS Distributions {
8677*c54f35caSApple OSS Distributions 	IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
8678*c54f35caSApple OSS Distributions 	if (me && !me->init(inOwner, inAction)) {
8679*c54f35caSApple OSS Distributions 		me->release();
8680*c54f35caSApple OSS Distributions 		me = NULL;
8681*c54f35caSApple OSS Distributions 	}
8682*c54f35caSApple OSS Distributions 	return me;
8683*c54f35caSApple OSS Distributions }
8684*c54f35caSApple OSS Distributions 
8685*c54f35caSApple OSS Distributions bool
init(IOService * inOwner,Action inAction)8686*c54f35caSApple OSS Distributions IOPMRequestQueue::init( IOService * inOwner, Action inAction )
8687*c54f35caSApple OSS Distributions {
8688*c54f35caSApple OSS Distributions 	if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction)) {
8689*c54f35caSApple OSS Distributions 		return false;
8690*c54f35caSApple OSS Distributions 	}
8691*c54f35caSApple OSS Distributions 
8692*c54f35caSApple OSS Distributions 	queue_init(&fQueue);
8693*c54f35caSApple OSS Distributions 	fLock = IOLockAlloc();
8694*c54f35caSApple OSS Distributions 	return fLock != NULL;
8695*c54f35caSApple OSS Distributions }
8696*c54f35caSApple OSS Distributions 
8697*c54f35caSApple OSS Distributions #pragma clang diagnostic pop
8698*c54f35caSApple OSS Distributions 
8699*c54f35caSApple OSS Distributions void
free(void)8700*c54f35caSApple OSS Distributions IOPMRequestQueue::free( void )
8701*c54f35caSApple OSS Distributions {
8702*c54f35caSApple OSS Distributions 	if (fLock) {
8703*c54f35caSApple OSS Distributions 		IOLockFree(fLock);
8704*c54f35caSApple OSS Distributions 		fLock = NULL;
8705*c54f35caSApple OSS Distributions 	}
8706*c54f35caSApple OSS Distributions 	return IOEventSource::free();
8707*c54f35caSApple OSS Distributions }
8708*c54f35caSApple OSS Distributions 
8709*c54f35caSApple OSS Distributions void
queuePMRequest(IOPMRequest * request)8710*c54f35caSApple OSS Distributions IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
8711*c54f35caSApple OSS Distributions {
8712*c54f35caSApple OSS Distributions 	uint64_t now = mach_continuous_time();
8713*c54f35caSApple OSS Distributions 
8714*c54f35caSApple OSS Distributions 	assert(request);
8715*c54f35caSApple OSS Distributions 	request->setTimestamp(now);
8716*c54f35caSApple OSS Distributions 	IOLockLock(fLock);
8717*c54f35caSApple OSS Distributions 	queue_enter(&fQueue, request, typeof(request), fCommandChain);
8718*c54f35caSApple OSS Distributions 	IOLockUnlock(fLock);
8719*c54f35caSApple OSS Distributions 	if (workLoop) {
8720*c54f35caSApple OSS Distributions 		signalWorkAvailable();
8721*c54f35caSApple OSS Distributions 	}
8722*c54f35caSApple OSS Distributions }
8723*c54f35caSApple OSS Distributions 
8724*c54f35caSApple OSS Distributions void
queuePMRequestChain(IOPMRequest ** requests,IOItemCount count)8725*c54f35caSApple OSS Distributions IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
8726*c54f35caSApple OSS Distributions {
8727*c54f35caSApple OSS Distributions 	IOPMRequest * next;
8728*c54f35caSApple OSS Distributions 	uint64_t now = mach_continuous_time();
8729*c54f35caSApple OSS Distributions 
8730*c54f35caSApple OSS Distributions 	assert(requests && count);
8731*c54f35caSApple OSS Distributions 	IOLockLock(fLock);
8732*c54f35caSApple OSS Distributions 	while (count--) {
8733*c54f35caSApple OSS Distributions 		next = *requests;
8734*c54f35caSApple OSS Distributions 		next->setTimestamp(now);
8735*c54f35caSApple OSS Distributions 		requests++;
8736*c54f35caSApple OSS Distributions 		queue_enter(&fQueue, next, typeof(next), fCommandChain);
8737*c54f35caSApple OSS Distributions 	}
8738*c54f35caSApple OSS Distributions 	IOLockUnlock(fLock);
8739*c54f35caSApple OSS Distributions 	if (workLoop) {
8740*c54f35caSApple OSS Distributions 		signalWorkAvailable();
8741*c54f35caSApple OSS Distributions 	}
8742*c54f35caSApple OSS Distributions }
8743*c54f35caSApple OSS Distributions 
8744*c54f35caSApple OSS Distributions bool
checkForWork(void)8745*c54f35caSApple OSS Distributions IOPMRequestQueue::checkForWork( void )
8746*c54f35caSApple OSS Distributions {
8747*c54f35caSApple OSS Distributions 	Action          dqAction = (Action) (void (*)(void))action;
8748*c54f35caSApple OSS Distributions 	IOPMRequest *   request;
8749*c54f35caSApple OSS Distributions 	IOService *     target;
8750*c54f35caSApple OSS Distributions 	int             dequeueCount = 0;
8751*c54f35caSApple OSS Distributions 	bool            more = false;
8752*c54f35caSApple OSS Distributions 
8753*c54f35caSApple OSS Distributions 	IOLockLock( fLock );
8754*c54f35caSApple OSS Distributions 
8755*c54f35caSApple OSS Distributions 	while (!queue_empty(&fQueue)) {
8756*c54f35caSApple OSS Distributions 		if (dequeueCount++ >= kMaxDequeueCount) {
8757*c54f35caSApple OSS Distributions 			// Allow other queues a chance to work
8758*c54f35caSApple OSS Distributions 			more = true;
8759*c54f35caSApple OSS Distributions 			break;
8760*c54f35caSApple OSS Distributions 		}
8761*c54f35caSApple OSS Distributions 
8762*c54f35caSApple OSS Distributions 		queue_remove_first(&fQueue, request, typeof(request), fCommandChain);
8763*c54f35caSApple OSS Distributions 		IOLockUnlock(fLock);
8764*c54f35caSApple OSS Distributions 		target = request->getTarget();
8765*c54f35caSApple OSS Distributions 		assert(target);
8766*c54f35caSApple OSS Distributions 		more |= (*dqAction)( target, request, this );
8767*c54f35caSApple OSS Distributions 		IOLockLock( fLock );
8768*c54f35caSApple OSS Distributions 	}
8769*c54f35caSApple OSS Distributions 
8770*c54f35caSApple OSS Distributions 	IOLockUnlock( fLock );
8771*c54f35caSApple OSS Distributions 	return more;
8772*c54f35caSApple OSS Distributions }
8773*c54f35caSApple OSS Distributions 
8774*c54f35caSApple OSS Distributions // MARK: -
8775*c54f35caSApple OSS Distributions // MARK: IOPMWorkQueue
8776*c54f35caSApple OSS Distributions 
8777*c54f35caSApple OSS Distributions //*********************************************************************************
8778*c54f35caSApple OSS Distributions // IOPMWorkQueue Class
8779*c54f35caSApple OSS Distributions //
8780*c54f35caSApple OSS Distributions // Queue of IOServicePM objects, each with a queue of IOPMRequest sharing the
8781*c54f35caSApple OSS Distributions // same target.
8782*c54f35caSApple OSS Distributions //*********************************************************************************
8783*c54f35caSApple OSS Distributions 
8784*c54f35caSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
8785*c54f35caSApple OSS Distributions 
8786*c54f35caSApple OSS Distributions IOPMWorkQueue *
create(IOService * inOwner,Action invoke,Action retire)8787*c54f35caSApple OSS Distributions IOPMWorkQueue::create( IOService * inOwner, Action invoke, Action retire )
8788*c54f35caSApple OSS Distributions {
8789*c54f35caSApple OSS Distributions 	IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
8790*c54f35caSApple OSS Distributions 	if (me && !me->init(inOwner, invoke, retire)) {
8791*c54f35caSApple OSS Distributions 		me->release();
8792*c54f35caSApple OSS Distributions 		me = NULL;
8793*c54f35caSApple OSS Distributions 	}
8794*c54f35caSApple OSS Distributions 	return me;
8795*c54f35caSApple OSS Distributions }
8796*c54f35caSApple OSS Distributions 
8797*c54f35caSApple OSS Distributions bool
init(IOService * inOwner,Action invoke,Action retire)8798*c54f35caSApple OSS Distributions IOPMWorkQueue::init( IOService * inOwner, Action invoke, Action retire )
8799*c54f35caSApple OSS Distributions {
8800*c54f35caSApple OSS Distributions 	if (!invoke || !retire ||
8801*c54f35caSApple OSS Distributions 	    !IOEventSource::init(inOwner, (IOEventSourceAction)NULL)) {
8802*c54f35caSApple OSS Distributions 		return false;
8803*c54f35caSApple OSS Distributions 	}
8804*c54f35caSApple OSS Distributions 
8805*c54f35caSApple OSS Distributions 	queue_init(&fWorkQueue);
8806*c54f35caSApple OSS Distributions 
8807*c54f35caSApple OSS Distributions 	fInvokeAction  = invoke;
8808*c54f35caSApple OSS Distributions 	fRetireAction  = retire;
8809*c54f35caSApple OSS Distributions 	fConsumerCount = fProducerCount = 0;
8810*c54f35caSApple OSS Distributions 
8811*c54f35caSApple OSS Distributions 	return true;
8812*c54f35caSApple OSS Distributions }
8813*c54f35caSApple OSS Distributions 
8814*c54f35caSApple OSS Distributions bool
queuePMRequest(IOPMRequest * request,IOServicePM * pwrMgt)8815*c54f35caSApple OSS Distributions IOPMWorkQueue::queuePMRequest( IOPMRequest * request, IOServicePM * pwrMgt )
8816*c54f35caSApple OSS Distributions {
8817*c54f35caSApple OSS Distributions 	queue_head_t *  requestQueue;
8818*c54f35caSApple OSS Distributions 	bool            more  = false;
8819*c54f35caSApple OSS Distributions 	bool            empty;
8820*c54f35caSApple OSS Distributions 
8821*c54f35caSApple OSS Distributions 	assert( request );
8822*c54f35caSApple OSS Distributions 	assert( pwrMgt );
8823*c54f35caSApple OSS Distributions 	assert( onThread());
8824*c54f35caSApple OSS Distributions 	assert( queue_next(&request->fCommandChain) ==
8825*c54f35caSApple OSS Distributions 	    queue_prev(&request->fCommandChain));
8826*c54f35caSApple OSS Distributions 
8827*c54f35caSApple OSS Distributions 	gIOPMBusyRequestCount++;
8828*c54f35caSApple OSS Distributions 
8829*c54f35caSApple OSS Distributions 	if (request->isQuiesceType()) {
8830*c54f35caSApple OSS Distributions 		if ((request->getTarget() == gIOPMRootNode) && !fQuiesceStartTime) {
8831*c54f35caSApple OSS Distributions 			// Attach new quiesce request to all quiesce blockers in the queue
8832*c54f35caSApple OSS Distributions 			fQuiesceStartTime = mach_absolute_time();
8833*c54f35caSApple OSS Distributions 			attachQuiesceRequest(request);
8834*c54f35caSApple OSS Distributions 			fQuiesceRequest = request;
8835*c54f35caSApple OSS Distributions 		}
8836*c54f35caSApple OSS Distributions 	} else if (fQuiesceRequest && request->isQuiesceBlocker()) {
8837*c54f35caSApple OSS Distributions 		// Attach the new quiesce blocker to the blocked quiesce request
8838*c54f35caSApple OSS Distributions 		request->attachNextRequest(fQuiesceRequest);
8839*c54f35caSApple OSS Distributions 	}
8840*c54f35caSApple OSS Distributions 
8841*c54f35caSApple OSS Distributions 	// Add new request to the tail of the per-service request queue.
8842*c54f35caSApple OSS Distributions 	// Then immediately check the request queue to minimize latency
8843*c54f35caSApple OSS Distributions 	// if the queue was empty.
8844*c54f35caSApple OSS Distributions 
8845*c54f35caSApple OSS Distributions 	requestQueue = &pwrMgt->RequestHead;
8846*c54f35caSApple OSS Distributions 	empty = queue_empty(requestQueue);
8847*c54f35caSApple OSS Distributions 	queue_enter(requestQueue, request, typeof(request), fCommandChain);
8848*c54f35caSApple OSS Distributions 	if (empty) {
8849*c54f35caSApple OSS Distributions 		more = checkRequestQueue(requestQueue, &empty);
8850*c54f35caSApple OSS Distributions 		if (!empty) {
8851*c54f35caSApple OSS Distributions 			// Request just added is blocked, add its target IOServicePM
8852*c54f35caSApple OSS Distributions 			// to the work queue.
8853*c54f35caSApple OSS Distributions 			assert( queue_next(&pwrMgt->WorkChain) ==
8854*c54f35caSApple OSS Distributions 			    queue_prev(&pwrMgt->WorkChain));
8855*c54f35caSApple OSS Distributions 
8856*c54f35caSApple OSS Distributions 			queue_enter(&fWorkQueue, pwrMgt, typeof(pwrMgt), WorkChain);
8857*c54f35caSApple OSS Distributions 			fQueueLength++;
8858*c54f35caSApple OSS Distributions 			PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
8859*c54f35caSApple OSS Distributions 			    fQueueLength, pwrMgt->Name, OBFUSCATE(pwrMgt));
8860*c54f35caSApple OSS Distributions 		}
8861*c54f35caSApple OSS Distributions 	}
8862*c54f35caSApple OSS Distributions 
8863*c54f35caSApple OSS Distributions 	return more;
8864*c54f35caSApple OSS Distributions }
8865*c54f35caSApple OSS Distributions 
8866*c54f35caSApple OSS Distributions bool
checkRequestQueue(queue_head_t * requestQueue,bool * empty)8867*c54f35caSApple OSS Distributions IOPMWorkQueue::checkRequestQueue( queue_head_t * requestQueue, bool * empty )
8868*c54f35caSApple OSS Distributions {
8869*c54f35caSApple OSS Distributions 	IOPMRequest *   request;
8870*c54f35caSApple OSS Distributions 	IOService *     target;
8871*c54f35caSApple OSS Distributions 	bool            more = false;
8872*c54f35caSApple OSS Distributions 	bool            done = false;
8873*c54f35caSApple OSS Distributions 
8874*c54f35caSApple OSS Distributions 	assert(!queue_empty(requestQueue));
8875*c54f35caSApple OSS Distributions 	do {
8876*c54f35caSApple OSS Distributions 		request = (typeof(request))queue_first(requestQueue);
8877*c54f35caSApple OSS Distributions 		if (request->isWorkBlocked()) {
8878*c54f35caSApple OSS Distributions 			break; // request dispatch blocked on attached request
8879*c54f35caSApple OSS Distributions 		}
8880*c54f35caSApple OSS Distributions 		target = request->getTarget();
8881*c54f35caSApple OSS Distributions 		if (fInvokeAction) {
8882*c54f35caSApple OSS Distributions 			done = (*fInvokeAction)( target, request, this );
8883*c54f35caSApple OSS Distributions 		} else {
8884*c54f35caSApple OSS Distributions 			PM_LOG("PM request 0x%x dropped\n", request->getType());
8885*c54f35caSApple OSS Distributions 			done = true;
8886*c54f35caSApple OSS Distributions 		}
8887*c54f35caSApple OSS Distributions 		if (!done) {
8888*c54f35caSApple OSS Distributions 			break; // PM state machine blocked
8889*c54f35caSApple OSS Distributions 		}
8890*c54f35caSApple OSS Distributions 		assert(gIOPMBusyRequestCount > 0);
8891*c54f35caSApple OSS Distributions 		if (gIOPMBusyRequestCount) {
8892*c54f35caSApple OSS Distributions 			gIOPMBusyRequestCount--;
8893*c54f35caSApple OSS Distributions 		}
8894*c54f35caSApple OSS Distributions 
8895*c54f35caSApple OSS Distributions 		if (request == fQuiesceRequest) {
8896*c54f35caSApple OSS Distributions 			fQuiesceRequest = NULL;
8897*c54f35caSApple OSS Distributions 		}
8898*c54f35caSApple OSS Distributions 
8899*c54f35caSApple OSS Distributions 		queue_remove_first(requestQueue, request, typeof(request), fCommandChain);
8900*c54f35caSApple OSS Distributions 		more |= (*fRetireAction)( target, request, this );
8901*c54f35caSApple OSS Distributions 		done = queue_empty(requestQueue);
8902*c54f35caSApple OSS Distributions 	} while (!done);
8903*c54f35caSApple OSS Distributions 
8904*c54f35caSApple OSS Distributions 	*empty = done;
8905*c54f35caSApple OSS Distributions 
8906*c54f35caSApple OSS Distributions 	if (more) {
8907*c54f35caSApple OSS Distributions 		// Retired a request that may unblock a previously visited request
8908*c54f35caSApple OSS Distributions 		// that is still waiting on the work queue. Must trigger another
8909*c54f35caSApple OSS Distributions 		// queue check.
8910*c54f35caSApple OSS Distributions 		fProducerCount++;
8911*c54f35caSApple OSS Distributions 	}
8912*c54f35caSApple OSS Distributions 
8913*c54f35caSApple OSS Distributions 	return more;
8914*c54f35caSApple OSS Distributions }
8915*c54f35caSApple OSS Distributions 
8916*c54f35caSApple OSS Distributions bool
checkForWork(void)8917*c54f35caSApple OSS Distributions IOPMWorkQueue::checkForWork( void )
8918*c54f35caSApple OSS Distributions {
8919*c54f35caSApple OSS Distributions 	IOServicePM *   entry;
8920*c54f35caSApple OSS Distributions 	IOServicePM *   next;
8921*c54f35caSApple OSS Distributions 	bool            more = false;
8922*c54f35caSApple OSS Distributions 	bool            empty;
8923*c54f35caSApple OSS Distributions 
8924*c54f35caSApple OSS Distributions #if WORK_QUEUE_STATS
8925*c54f35caSApple OSS Distributions 	fStatCheckForWork++;
8926*c54f35caSApple OSS Distributions #endif
8927*c54f35caSApple OSS Distributions 
8928*c54f35caSApple OSS Distributions 	// Iterate over all IOServicePM entries in the work queue,
8929*c54f35caSApple OSS Distributions 	// and check each entry's request queue.
8930*c54f35caSApple OSS Distributions 
8931*c54f35caSApple OSS Distributions 	while (fConsumerCount != fProducerCount) {
8932*c54f35caSApple OSS Distributions 		PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
8933*c54f35caSApple OSS Distributions 		    fProducerCount, fConsumerCount);
8934*c54f35caSApple OSS Distributions 
8935*c54f35caSApple OSS Distributions 		fConsumerCount = fProducerCount;
8936*c54f35caSApple OSS Distributions 
8937*c54f35caSApple OSS Distributions #if WORK_QUEUE_STATS
8938*c54f35caSApple OSS Distributions 		if (queue_empty(&fWorkQueue)) {
8939*c54f35caSApple OSS Distributions 			fStatQueueEmpty++;
8940*c54f35caSApple OSS Distributions 			break;
8941*c54f35caSApple OSS Distributions 		}
8942*c54f35caSApple OSS Distributions 		fStatScanEntries++;
8943*c54f35caSApple OSS Distributions 		uint32_t cachedWorkCount = gIOPMWorkInvokeCount;
8944*c54f35caSApple OSS Distributions #endif
8945*c54f35caSApple OSS Distributions 
8946*c54f35caSApple OSS Distributions 		__IGNORE_WCASTALIGN(entry = (typeof(entry))queue_first(&fWorkQueue));
8947*c54f35caSApple OSS Distributions 		while (!queue_end(&fWorkQueue, (queue_entry_t) entry)) {
8948*c54f35caSApple OSS Distributions 			more |= checkRequestQueue(&entry->RequestHead, &empty);
8949*c54f35caSApple OSS Distributions 
8950*c54f35caSApple OSS Distributions 			// Get next entry, points to head if current entry is last.
8951*c54f35caSApple OSS Distributions 			__IGNORE_WCASTALIGN(next = (typeof(next))queue_next(&entry->WorkChain));
8952*c54f35caSApple OSS Distributions 
8953*c54f35caSApple OSS Distributions 			// if request queue is empty, remove IOServicePM from work queue.
8954*c54f35caSApple OSS Distributions 			if (empty) {
8955*c54f35caSApple OSS Distributions 				assert(fQueueLength);
8956*c54f35caSApple OSS Distributions 				if (fQueueLength) {
8957*c54f35caSApple OSS Distributions 					fQueueLength--;
8958*c54f35caSApple OSS Distributions 				}
8959*c54f35caSApple OSS Distributions 				PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
8960*c54f35caSApple OSS Distributions 				    fQueueLength, entry->Name, OBFUSCATE(entry));
8961*c54f35caSApple OSS Distributions 				queue_remove(&fWorkQueue, entry, typeof(entry), WorkChain);
8962*c54f35caSApple OSS Distributions 			}
8963*c54f35caSApple OSS Distributions 			entry = next;
8964*c54f35caSApple OSS Distributions 		}
8965*c54f35caSApple OSS Distributions 
8966*c54f35caSApple OSS Distributions #if WORK_QUEUE_STATS
8967*c54f35caSApple OSS Distributions 		if (cachedWorkCount == gIOPMWorkInvokeCount) {
8968*c54f35caSApple OSS Distributions 			fStatNoWorkDone++;
8969*c54f35caSApple OSS Distributions 		}
8970*c54f35caSApple OSS Distributions #endif
8971*c54f35caSApple OSS Distributions 	}
8972*c54f35caSApple OSS Distributions 
8973*c54f35caSApple OSS Distributions 	return more;
8974*c54f35caSApple OSS Distributions }
8975*c54f35caSApple OSS Distributions 
8976*c54f35caSApple OSS Distributions void
signalWorkAvailable(void)8977*c54f35caSApple OSS Distributions IOPMWorkQueue::signalWorkAvailable( void )
8978*c54f35caSApple OSS Distributions {
8979*c54f35caSApple OSS Distributions 	fProducerCount++;
8980*c54f35caSApple OSS Distributions 	IOEventSource::signalWorkAvailable();
8981*c54f35caSApple OSS Distributions }
8982*c54f35caSApple OSS Distributions 
8983*c54f35caSApple OSS Distributions void
incrementProducerCount(void)8984*c54f35caSApple OSS Distributions IOPMWorkQueue::incrementProducerCount( void )
8985*c54f35caSApple OSS Distributions {
8986*c54f35caSApple OSS Distributions 	fProducerCount++;
8987*c54f35caSApple OSS Distributions }
8988*c54f35caSApple OSS Distributions 
8989*c54f35caSApple OSS Distributions void
attachQuiesceRequest(IOPMRequest * quiesceRequest)8990*c54f35caSApple OSS Distributions IOPMWorkQueue::attachQuiesceRequest( IOPMRequest * quiesceRequest )
8991*c54f35caSApple OSS Distributions {
8992*c54f35caSApple OSS Distributions 	IOServicePM *   entry;
8993*c54f35caSApple OSS Distributions 	IOPMRequest *   request;
8994*c54f35caSApple OSS Distributions 
8995*c54f35caSApple OSS Distributions 	if (queue_empty(&fWorkQueue)) {
8996*c54f35caSApple OSS Distributions 		return;
8997*c54f35caSApple OSS Distributions 	}
8998*c54f35caSApple OSS Distributions 
8999*c54f35caSApple OSS Distributions 	queue_iterate(&fWorkQueue, entry, typeof(entry), WorkChain)
9000*c54f35caSApple OSS Distributions 	{
9001*c54f35caSApple OSS Distributions 		queue_iterate(&entry->RequestHead, request, typeof(request), fCommandChain)
9002*c54f35caSApple OSS Distributions 		{
9003*c54f35caSApple OSS Distributions 			// Attach the quiesce request to any request in the queue that
9004*c54f35caSApple OSS Distributions 			// is not linked to a next request. These requests will block
9005*c54f35caSApple OSS Distributions 			// the quiesce request.
9006*c54f35caSApple OSS Distributions 
9007*c54f35caSApple OSS Distributions 			if (request->isQuiesceBlocker()) {
9008*c54f35caSApple OSS Distributions 				request->attachNextRequest(quiesceRequest);
9009*c54f35caSApple OSS Distributions 			}
9010*c54f35caSApple OSS Distributions 		}
9011*c54f35caSApple OSS Distributions 	}
9012*c54f35caSApple OSS Distributions }
9013*c54f35caSApple OSS Distributions 
9014*c54f35caSApple OSS Distributions void
finishQuiesceRequest(IOPMRequest * quiesceRequest)9015*c54f35caSApple OSS Distributions IOPMWorkQueue::finishQuiesceRequest( IOPMRequest * quiesceRequest )
9016*c54f35caSApple OSS Distributions {
9017*c54f35caSApple OSS Distributions 	if (fQuiesceRequest && (quiesceRequest == fQuiesceRequest) &&
9018*c54f35caSApple OSS Distributions 	    (fQuiesceStartTime != 0)) {
9019*c54f35caSApple OSS Distributions 		fInvokeAction = NULL;
9020*c54f35caSApple OSS Distributions 		fQuiesceFinishTime = mach_absolute_time();
9021*c54f35caSApple OSS Distributions 	}
9022*c54f35caSApple OSS Distributions }
9023*c54f35caSApple OSS Distributions 
9024*c54f35caSApple OSS Distributions // MARK: -
9025*c54f35caSApple OSS Distributions // MARK: IOPMCompletionQueue
9026*c54f35caSApple OSS Distributions 
9027*c54f35caSApple OSS Distributions //*********************************************************************************
9028*c54f35caSApple OSS Distributions // IOPMCompletionQueue Class
9029*c54f35caSApple OSS Distributions //*********************************************************************************
9030*c54f35caSApple OSS Distributions 
9031*c54f35caSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMCompletionQueue, IOEventSource );
9032*c54f35caSApple OSS Distributions 
9033*c54f35caSApple OSS Distributions #pragma clang diagnostic push
9034*c54f35caSApple OSS Distributions #pragma clang diagnostic ignored "-Wcast-function-type"
9035*c54f35caSApple OSS Distributions 
9036*c54f35caSApple OSS Distributions IOPMCompletionQueue *
create(IOService * inOwner,Action inAction)9037*c54f35caSApple OSS Distributions IOPMCompletionQueue::create( IOService * inOwner, Action inAction )
9038*c54f35caSApple OSS Distributions {
9039*c54f35caSApple OSS Distributions 	IOPMCompletionQueue * me = OSTypeAlloc(IOPMCompletionQueue);
9040*c54f35caSApple OSS Distributions 	if (me && !me->init(inOwner, inAction)) {
9041*c54f35caSApple OSS Distributions 		me->release();
9042*c54f35caSApple OSS Distributions 		me = NULL;
9043*c54f35caSApple OSS Distributions 	}
9044*c54f35caSApple OSS Distributions 	return me;
9045*c54f35caSApple OSS Distributions }
9046*c54f35caSApple OSS Distributions 
9047*c54f35caSApple OSS Distributions bool
init(IOService * inOwner,Action inAction)9048*c54f35caSApple OSS Distributions IOPMCompletionQueue::init( IOService * inOwner, Action inAction )
9049*c54f35caSApple OSS Distributions {
9050*c54f35caSApple OSS Distributions 	if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction)) {
9051*c54f35caSApple OSS Distributions 		return false;
9052*c54f35caSApple OSS Distributions 	}
9053*c54f35caSApple OSS Distributions 
9054*c54f35caSApple OSS Distributions 	queue_init(&fQueue);
9055*c54f35caSApple OSS Distributions 	return true;
9056*c54f35caSApple OSS Distributions }
9057*c54f35caSApple OSS Distributions 
9058*c54f35caSApple OSS Distributions 
9059*c54f35caSApple OSS Distributions bool
queuePMRequest(IOPMRequest * request)9060*c54f35caSApple OSS Distributions IOPMCompletionQueue::queuePMRequest( IOPMRequest * request )
9061*c54f35caSApple OSS Distributions {
9062*c54f35caSApple OSS Distributions 	bool more;
9063*c54f35caSApple OSS Distributions 
9064*c54f35caSApple OSS Distributions 	assert(request);
9065*c54f35caSApple OSS Distributions 	// unblock dependent request
9066*c54f35caSApple OSS Distributions 	more = request->detachNextRequest();
9067*c54f35caSApple OSS Distributions 	queue_enter(&fQueue, request, typeof(request), fCommandChain);
9068*c54f35caSApple OSS Distributions 	return more;
9069*c54f35caSApple OSS Distributions }
9070*c54f35caSApple OSS Distributions 
9071*c54f35caSApple OSS Distributions bool
checkForWork(void)9072*c54f35caSApple OSS Distributions IOPMCompletionQueue::checkForWork( void )
9073*c54f35caSApple OSS Distributions {
9074*c54f35caSApple OSS Distributions 	Action          dqAction = (Action) action;
9075*c54f35caSApple OSS Distributions 	IOPMRequest *   request;
9076*c54f35caSApple OSS Distributions 	IOPMRequest *   next;
9077*c54f35caSApple OSS Distributions 	IOService *     target;
9078*c54f35caSApple OSS Distributions 	bool            more = false;
9079*c54f35caSApple OSS Distributions 
9080*c54f35caSApple OSS Distributions 	request = (typeof(request))queue_first(&fQueue);
9081*c54f35caSApple OSS Distributions 	while (!queue_end(&fQueue, (queue_entry_t) request)) {
9082*c54f35caSApple OSS Distributions 		next = (typeof(next))queue_next(&request->fCommandChain);
9083*c54f35caSApple OSS Distributions 		if (!request->isFreeBlocked()) {
9084*c54f35caSApple OSS Distributions 			queue_remove(&fQueue, request, typeof(request), fCommandChain);
9085*c54f35caSApple OSS Distributions 			target = request->getTarget();
9086*c54f35caSApple OSS Distributions 			assert(target);
9087*c54f35caSApple OSS Distributions 			more |= (*dqAction)( target, request, this );
9088*c54f35caSApple OSS Distributions 		}
9089*c54f35caSApple OSS Distributions 		request = next;
9090*c54f35caSApple OSS Distributions 	}
9091*c54f35caSApple OSS Distributions 
9092*c54f35caSApple OSS Distributions 	return more;
9093*c54f35caSApple OSS Distributions }
9094*c54f35caSApple OSS Distributions 
9095*c54f35caSApple OSS Distributions #pragma clang diagnostic pop
9096*c54f35caSApple OSS Distributions 
9097*c54f35caSApple OSS Distributions // MARK: -
9098*c54f35caSApple OSS Distributions // MARK: IOServicePM
9099*c54f35caSApple OSS Distributions 
OSDefineMetaClassAndStructors(IOServicePM,OSObject)9100*c54f35caSApple OSS Distributions OSDefineMetaClassAndStructors(IOServicePM, OSObject)
9101*c54f35caSApple OSS Distributions 
9102*c54f35caSApple OSS Distributions //*********************************************************************************
9103*c54f35caSApple OSS Distributions // serialize
9104*c54f35caSApple OSS Distributions //
9105*c54f35caSApple OSS Distributions // Serialize IOServicePM for debugging.
9106*c54f35caSApple OSS Distributions //*********************************************************************************
9107*c54f35caSApple OSS Distributions 
9108*c54f35caSApple OSS Distributions static void
9109*c54f35caSApple OSS Distributions setPMProperty( OSDictionary * dict, const char * key, uint64_t value )
9110*c54f35caSApple OSS Distributions {
9111*c54f35caSApple OSS Distributions 	OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
9112*c54f35caSApple OSS Distributions 	if (num) {
9113*c54f35caSApple OSS Distributions 		dict->setObject(key, num);
9114*c54f35caSApple OSS Distributions 		num->release();
9115*c54f35caSApple OSS Distributions 	}
9116*c54f35caSApple OSS Distributions }
9117*c54f35caSApple OSS Distributions 
9118*c54f35caSApple OSS Distributions IOReturn
gatedSerialize(OSSerialize * s) const9119*c54f35caSApple OSS Distributions IOServicePM::gatedSerialize( OSSerialize * s  ) const
9120*c54f35caSApple OSS Distributions {
9121*c54f35caSApple OSS Distributions 	OSDictionary *  dict;
9122*c54f35caSApple OSS Distributions 	bool            ok = false;
9123*c54f35caSApple OSS Distributions 	int             powerClamp = -1;
9124*c54f35caSApple OSS Distributions 	int             dictSize = 6;
9125*c54f35caSApple OSS Distributions 
9126*c54f35caSApple OSS Distributions 	if (IdleTimerPeriod) {
9127*c54f35caSApple OSS Distributions 		dictSize += 4;
9128*c54f35caSApple OSS Distributions 	}
9129*c54f35caSApple OSS Distributions 
9130*c54f35caSApple OSS Distributions 	if (PMActions.state & kPMActionsStatePowerClamped) {
9131*c54f35caSApple OSS Distributions 		dictSize += 1;
9132*c54f35caSApple OSS Distributions 		powerClamp = 0;
9133*c54f35caSApple OSS Distributions 		if (PMActions.flags &
9134*c54f35caSApple OSS Distributions 		    (kPMActionsFlagIsDisplayWrangler | kPMActionsFlagIsGraphicsDriver)) {
9135*c54f35caSApple OSS Distributions 			powerClamp++;
9136*c54f35caSApple OSS Distributions 		}
9137*c54f35caSApple OSS Distributions 	}
9138*c54f35caSApple OSS Distributions 
9139*c54f35caSApple OSS Distributions #if WORK_QUEUE_STATS
9140*c54f35caSApple OSS Distributions 	if (gIOPMRootNode == ControllingDriver) {
9141*c54f35caSApple OSS Distributions 		dictSize += 4;
9142*c54f35caSApple OSS Distributions 	}
9143*c54f35caSApple OSS Distributions #endif
9144*c54f35caSApple OSS Distributions 
9145*c54f35caSApple OSS Distributions 	if (PowerClients) {
9146*c54f35caSApple OSS Distributions 		dict = OSDictionary::withDictionary(
9147*c54f35caSApple OSS Distributions 			PowerClients, PowerClients->getCount() + dictSize);
9148*c54f35caSApple OSS Distributions 	} else {
9149*c54f35caSApple OSS Distributions 		dict = OSDictionary::withCapacity(dictSize);
9150*c54f35caSApple OSS Distributions 	}
9151*c54f35caSApple OSS Distributions 
9152*c54f35caSApple OSS Distributions 	if (dict) {
9153*c54f35caSApple OSS Distributions 		setPMProperty(dict, "CurrentPowerState", CurrentPowerState);
9154*c54f35caSApple OSS Distributions 		setPMProperty(dict, "CapabilityFlags", CurrentCapabilityFlags);
9155*c54f35caSApple OSS Distributions 		if (NumberOfPowerStates) {
9156*c54f35caSApple OSS Distributions 			setPMProperty(dict, "MaxPowerState", NumberOfPowerStates - 1);
9157*c54f35caSApple OSS Distributions 		}
9158*c54f35caSApple OSS Distributions 		if (DesiredPowerState != CurrentPowerState) {
9159*c54f35caSApple OSS Distributions 			setPMProperty(dict, "DesiredPowerState", DesiredPowerState);
9160*c54f35caSApple OSS Distributions 		}
9161*c54f35caSApple OSS Distributions 		if (kIOPM_Finished != MachineState) {
9162*c54f35caSApple OSS Distributions 			setPMProperty(dict, "MachineState", MachineState);
9163*c54f35caSApple OSS Distributions 		}
9164*c54f35caSApple OSS Distributions 		if (DeviceOverrideEnabled) {
9165*c54f35caSApple OSS Distributions 			dict->setObject("PowerOverrideOn", kOSBooleanTrue);
9166*c54f35caSApple OSS Distributions 		}
9167*c54f35caSApple OSS Distributions 		if (powerClamp >= 0) {
9168*c54f35caSApple OSS Distributions 			setPMProperty(dict, "PowerClamp", powerClamp);
9169*c54f35caSApple OSS Distributions 		}
9170*c54f35caSApple OSS Distributions 
9171*c54f35caSApple OSS Distributions 		if (IdleTimerPeriod) {
9172*c54f35caSApple OSS Distributions 			AbsoluteTime    now;
9173*c54f35caSApple OSS Distributions 			AbsoluteTime    delta;
9174*c54f35caSApple OSS Distributions 			uint64_t        nsecs;
9175*c54f35caSApple OSS Distributions 
9176*c54f35caSApple OSS Distributions 			clock_get_uptime(&now);
9177*c54f35caSApple OSS Distributions 
9178*c54f35caSApple OSS Distributions 			// The idle timer period in milliseconds
9179*c54f35caSApple OSS Distributions 			setPMProperty(dict, "IdleTimerPeriod", NextIdleTimerPeriod * 1000ULL);
9180*c54f35caSApple OSS Distributions 
9181*c54f35caSApple OSS Distributions 			// Number of tickles since the last idle timer expiration
9182*c54f35caSApple OSS Distributions 			setPMProperty(dict, "ActivityTickles", ActivityTickleCount);
9183*c54f35caSApple OSS Distributions 
9184*c54f35caSApple OSS Distributions 			if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp)) {
9185*c54f35caSApple OSS Distributions 				// Milliseconds since the last activity tickle
9186*c54f35caSApple OSS Distributions 				delta = now;
9187*c54f35caSApple OSS Distributions 				SUB_ABSOLUTETIME(&delta, &DeviceActiveTimestamp);
9188*c54f35caSApple OSS Distributions 				absolutetime_to_nanoseconds(delta, &nsecs);
9189*c54f35caSApple OSS Distributions 				setPMProperty(dict, "TimeSinceLastTickle", NS_TO_MS(nsecs));
9190*c54f35caSApple OSS Distributions 			}
9191*c54f35caSApple OSS Distributions 
9192*c54f35caSApple OSS Distributions 			if (!IdleTimerStopped && AbsoluteTime_to_scalar(&IdleTimerStartTime)) {
9193*c54f35caSApple OSS Distributions 				// Idle timer elapsed time in milliseconds
9194*c54f35caSApple OSS Distributions 				delta = now;
9195*c54f35caSApple OSS Distributions 				SUB_ABSOLUTETIME(&delta, &IdleTimerStartTime);
9196*c54f35caSApple OSS Distributions 				absolutetime_to_nanoseconds(delta, &nsecs);
9197*c54f35caSApple OSS Distributions 				setPMProperty(dict, "IdleTimerElapsedTime", NS_TO_MS(nsecs));
9198*c54f35caSApple OSS Distributions 			}
9199*c54f35caSApple OSS Distributions 		}
9200*c54f35caSApple OSS Distributions 
9201*c54f35caSApple OSS Distributions #if WORK_QUEUE_STATS
9202*c54f35caSApple OSS Distributions 		if (gIOPMRootNode == Owner) {
9203*c54f35caSApple OSS Distributions 			setPMProperty(dict, "WQ-CheckForWork",
9204*c54f35caSApple OSS Distributions 			    gIOPMWorkQueue->fStatCheckForWork);
9205*c54f35caSApple OSS Distributions 			setPMProperty(dict, "WQ-ScanEntries",
9206*c54f35caSApple OSS Distributions 			    gIOPMWorkQueue->fStatScanEntries);
9207*c54f35caSApple OSS Distributions 			setPMProperty(dict, "WQ-QueueEmpty",
9208*c54f35caSApple OSS Distributions 			    gIOPMWorkQueue->fStatQueueEmpty);
9209*c54f35caSApple OSS Distributions 			setPMProperty(dict, "WQ-NoWorkDone",
9210*c54f35caSApple OSS Distributions 			    gIOPMWorkQueue->fStatNoWorkDone);
9211*c54f35caSApple OSS Distributions 		}
9212*c54f35caSApple OSS Distributions #endif
9213*c54f35caSApple OSS Distributions 
9214*c54f35caSApple OSS Distributions 		if (HasAdvisoryDesire && !gIOPMAdvisoryTickleEnabled) {
9215*c54f35caSApple OSS Distributions 			// Don't report advisory tickle when it has no influence
9216*c54f35caSApple OSS Distributions 			dict->removeObject(gIOPMPowerClientAdvisoryTickle);
9217*c54f35caSApple OSS Distributions 		}
9218*c54f35caSApple OSS Distributions 
9219*c54f35caSApple OSS Distributions 		ok = dict->serialize(s);
9220*c54f35caSApple OSS Distributions 		dict->release();
9221*c54f35caSApple OSS Distributions 	}
9222*c54f35caSApple OSS Distributions 
9223*c54f35caSApple OSS Distributions 	return ok ? kIOReturnSuccess : kIOReturnNoMemory;
9224*c54f35caSApple OSS Distributions }
9225*c54f35caSApple OSS Distributions 
9226*c54f35caSApple OSS Distributions bool
serialize(OSSerialize * s) const9227*c54f35caSApple OSS Distributions IOServicePM::serialize( OSSerialize * s ) const
9228*c54f35caSApple OSS Distributions {
9229*c54f35caSApple OSS Distributions 	IOReturn ret = kIOReturnNotReady;
9230*c54f35caSApple OSS Distributions 
9231*c54f35caSApple OSS Distributions 	if (gIOPMWatchDogThread == current_thread()) {
9232*c54f35caSApple OSS Distributions 		// Calling without lock as this data is collected for debug purpose, before reboot.
9233*c54f35caSApple OSS Distributions 		// The workloop is probably already hung in state machine.
9234*c54f35caSApple OSS Distributions 		ret = gatedSerialize(s);
9235*c54f35caSApple OSS Distributions 	} else if (gIOPMWorkLoop) {
9236*c54f35caSApple OSS Distributions 		ret = gIOPMWorkLoop->runAction(
9237*c54f35caSApple OSS Distributions 			OSMemberFunctionCast(IOWorkLoop::Action, this, &IOServicePM::gatedSerialize),
9238*c54f35caSApple OSS Distributions 			(OSObject *) this, (void *) s);
9239*c54f35caSApple OSS Distributions 	}
9240*c54f35caSApple OSS Distributions 
9241*c54f35caSApple OSS Distributions 	return kIOReturnSuccess == ret;
9242*c54f35caSApple OSS Distributions }
9243*c54f35caSApple OSS Distributions 
9244*c54f35caSApple OSS Distributions void
pmPrint(uint32_t event,uintptr_t param1,uintptr_t param2) const9245*c54f35caSApple OSS Distributions IOServicePM::pmPrint(
9246*c54f35caSApple OSS Distributions 	uint32_t        event,
9247*c54f35caSApple OSS Distributions 	uintptr_t       param1,
9248*c54f35caSApple OSS Distributions 	uintptr_t       param2 ) const
9249*c54f35caSApple OSS Distributions {
9250*c54f35caSApple OSS Distributions 	gPlatform->PMLog(Name, event, param1, param2);
9251*c54f35caSApple OSS Distributions }
9252*c54f35caSApple OSS Distributions 
9253*c54f35caSApple OSS Distributions void
pmTrace(uint32_t event,uint32_t eventFunc,uintptr_t param1,uintptr_t param2) const9254*c54f35caSApple OSS Distributions IOServicePM::pmTrace(
9255*c54f35caSApple OSS Distributions 	uint32_t        event,
9256*c54f35caSApple OSS Distributions 	uint32_t        eventFunc,
9257*c54f35caSApple OSS Distributions 	uintptr_t       param1,
9258*c54f35caSApple OSS Distributions 	uintptr_t       param2 ) const
9259*c54f35caSApple OSS Distributions {
9260*c54f35caSApple OSS Distributions 	uintptr_t nameAsArg = 0;
9261*c54f35caSApple OSS Distributions 
9262*c54f35caSApple OSS Distributions 	assert(event < KDBG_CODE_MAX);
9263*c54f35caSApple OSS Distributions 	assert((eventFunc & ~KDBG_FUNC_MASK) == 0);
9264*c54f35caSApple OSS Distributions 
9265*c54f35caSApple OSS Distributions 	// Copy the first characters of the name into an uintptr_t.
9266*c54f35caSApple OSS Distributions 	// NULL termination is not required.
9267*c54f35caSApple OSS Distributions 	strncpy((char*)&nameAsArg, Name, sizeof(nameAsArg));
9268*c54f35caSApple OSS Distributions 
9269*c54f35caSApple OSS Distributions #if defined(XNU_TARGET_OS_OSX)
9270*c54f35caSApple OSS Distributions 	KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, IODBG_POWER(event) | eventFunc, nameAsArg,
9271*c54f35caSApple OSS Distributions 	    (uintptr_t)Owner->getRegistryEntryID(), (uintptr_t)(OBFUSCATE(param1)),
9272*c54f35caSApple OSS Distributions 	    (uintptr_t)(OBFUSCATE(param2)), 0);
9273*c54f35caSApple OSS Distributions #else
9274*c54f35caSApple OSS Distributions 	IOTimeStampConstant(IODBG_POWER(event) | eventFunc, nameAsArg, (uintptr_t)Owner->getRegistryEntryID(), (uintptr_t)(OBFUSCATE(param1)), (uintptr_t)(OBFUSCATE(param2)));
9275*c54f35caSApple OSS Distributions #endif
9276*c54f35caSApple OSS Distributions }
9277