]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOServicePM.cpp
xnu-2422.90.20.tar.gz
[apple/xnu.git] / iokit / Kernel / IOServicePM.cpp
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
91447636 28
6d2010ae
A
29//#undef IOASSERT
30//#define IOASSERT 1
31
91447636 32#include <IOKit/assert.h>
91447636
A
33#include <IOKit/IOKitDebug.h>
34#include <IOKit/IOLib.h>
35#include <IOKit/IOMessage.h>
36#include <IOKit/IOPlatformExpert.h>
37#include <IOKit/IOService.h>
6d2010ae 38#include <IOKit/IOEventSource.h>
1c79356b 39#include <IOKit/IOWorkLoop.h>
2d21ac55 40#include <IOKit/IOCommand.h>
4b17d6b6 41#include <IOKit/IOTimeStamp.h>
39236c6e 42#include <IOKit/IOReportMacros.h>
1c79356b 43
2d21ac55 44#include <IOKit/pwr_mgt/IOPMlog.h>
91447636
A
45#include <IOKit/pwr_mgt/IOPMinformee.h>
46#include <IOKit/pwr_mgt/IOPMinformeeList.h>
91447636
A
47#include <IOKit/pwr_mgt/IOPowerConnection.h>
48#include <IOKit/pwr_mgt/RootDomain.h>
6d2010ae 49#include <IOKit/pwr_mgt/IOPMPrivate.h>
9bccf70c 50
2d21ac55 51#include <sys/proc.h>
316670eb 52#include <sys/proc_internal.h>
6d2010ae 53#include <libkern/OSDebug.h>
39236c6e 54#include <kern/thread.h>
0c530ab8 55
91447636
A
56// Required for notification instrumentation
57#include "IOServicePrivate.h"
2d21ac55
A
58#include "IOServicePMPrivate.h"
59#include "IOKitKernelInternal.h"
9bccf70c 60
39236c6e 61
2d21ac55 62static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
6d2010ae 63static void idle_timer_expired(thread_call_param_t, thread_call_param_t);
b0d623f7
A
64static void tellKernelClientApplier(OSObject * object, void * arg);
65static void tellAppClientApplier(OSObject * object, void * arg);
9bccf70c 66
2d21ac55
A
67static uint64_t computeTimeDeltaNS( const AbsoluteTime * start )
68{
69 AbsoluteTime now;
70 uint64_t nsec;
9bccf70c 71
2d21ac55
A
72 clock_get_uptime(&now);
73 SUB_ABSOLUTETIME(&now, start);
74 absolutetime_to_nanoseconds(now, &nsec);
75 return nsec;
76}
1c79356b 77
b0d623f7 78#if PM_VARS_SUPPORT
2d21ac55 79OSDefineMetaClassAndStructors(IOPMprot, OSObject)
b0d623f7 80#endif
1c79356b 81
6d2010ae
A
82// Container class for recording system power events
83OSDefineMetaClassAndStructors( PMEventDetails, OSObject );
84
85//******************************************************************************
2d21ac55 86// Globals
6d2010ae 87//******************************************************************************
1c79356b 88
bd504ef0
A
89static bool gIOPMInitialized = false;
90static uint32_t gIOPMBusyCount = 0;
91static uint32_t gIOPMWorkCount = 0;
92static uint32_t gIOPMTickleGeneration = 0;
93static IOWorkLoop * gIOPMWorkLoop = 0;
94static IOPMRequestQueue * gIOPMRequestQueue = 0;
95static IOPMRequestQueue * gIOPMReplyQueue = 0;
96static IOPMWorkQueue * gIOPMWorkQueue = 0;
97static IOPMCompletionQueue * gIOPMFreeQueue = 0;
98static IOPMRequest * gIOPMRequest = 0;
99static IOService * gIOPMRootNode = 0;
100static IOPlatformExpert * gPlatform = 0;
b0d623f7 101
39236c6e
A
102const OSSymbol * gIOPMPowerClientDevice = 0;
103const OSSymbol * gIOPMPowerClientDriver = 0;
104const OSSymbol * gIOPMPowerClientChildProxy = 0;
105const OSSymbol * gIOPMPowerClientChildren = 0;
106const OSSymbol * gIOPMPowerClientRootDomain = 0;
b0d623f7 107
db609669
A
108static const OSSymbol * gIOPMPowerClientAdvisoryTickle = 0;
109static bool gIOPMAdvisoryTickleEnabled = true;
39236c6e 110static thread_t gIOPMWatchDogThread = NULL;
db609669 111
b0d623f7
A
112static uint32_t getPMRequestType( void )
113{
114 uint32_t type = kIOPMRequestTypeInvalid;
115 if (gIOPMRequest)
116 type = gIOPMRequest->getType();
117 return type;
118}
1c79356b 119
39236c6e
A
120static IOPMRequestTag getPMRequestTag( void )
121{
122 IOPMRequestTag tag = 0;
123 if (gIOPMRequest &&
124 (gIOPMRequest->getType() == kIOPMRequestTypeRequestPowerStateOverride))
125 {
126 tag = gIOPMRequest->fRequestTag;
127 }
128 return tag;
129}
130
6d2010ae 131//******************************************************************************
2d21ac55 132// Macros
6d2010ae 133//******************************************************************************
1c79356b 134
39236c6e
A
135#define OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x)))
136
137#define PM_ERROR(x...) do { kprintf(x);IOLog(x); \
138 IOService::getPMRootDomain()->sleepWakeDebugLog(x); \
139 } while (false)
6d2010ae
A
140#define PM_LOG(x...) do { kprintf(x); } while (false)
141
142#define PM_LOG1(x...) do { \
143 if (kIOLogDebugPower & gIOKitDebug) \
144 kprintf(x); } while (false)
145
146#define PM_LOG2(x...) do { \
147 if (kIOLogDebugPower & gIOKitDebug) \
148 kprintf(x); } while (false)
55e303ae 149
6d2010ae
A
150#if 0
151#define PM_LOG3(x...) do { kprintf(x); } while (false)
152#else
153#define PM_LOG3(x...)
154#endif
155
156#define RD_LOG(x...) do { \
157 if ((kIOLogPMRootDomain & gIOKitDebug) && \
39236c6e
A
158 (getPMRootDomain() == this)) { \
159 kprintf("PMRD: " x); \
160 getPMRootDomain()->sleepWakeDebugLog(x); \
161 }} while (false)
2d21ac55
A
162#define PM_ASSERT_IN_GATE(x) \
163do { \
164 assert(gIOPMWorkLoop->inGate()); \
165} while(false)
1c79356b 166
b0d623f7
A
167#define PM_LOCK() IOLockLock(fPMLock)
168#define PM_UNLOCK() IOLockUnlock(fPMLock)
6d2010ae 169#define PM_LOCK_SLEEP(event, dl) IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
b0d623f7 170#define PM_LOCK_WAKEUP(event) IOLockWakeup(fPMLock, event, false)
2d21ac55 171
b0d623f7 172#define ns_per_us 1000
316670eb 173#define k30Seconds (30*1000000)
b0d623f7
A
174#define kMinAckTimeoutTicks (10*1000000)
175#define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
176#define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
177#define kPwrMgtKey "IOPowerManagement"
2d21ac55 178
4b17d6b6
A
179#define OUR_PMLog(t, a, b) do { \
180 if (gIOKitDebug & kIOLogPower) \
181 pwrMgt->pmPrint(t, a, b); \
182 if (gIOKitTrace & kIOTracePowerMgmt) \
183 pwrMgt->pmTrace(t, a, b); \
184 } while(0)
2d21ac55 185
b0d623f7 186#define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
6d2010ae 187#define NS_TO_US(nsec) ((int)((nsec) / 1000ULL))
2d21ac55 188
b0d623f7 189#define SUPPORT_IDLE_CANCEL 1
593a1d5f 190
39236c6e
A
191#define kIOPMPowerStateMax 0xFFFFFFFF
192#define kInvalidTicklePowerState kIOPMPowerStateMax
db609669
A
193
194#define kNoTickleCancelWindow (60ULL * 1000ULL * 1000ULL * 1000ULL)
b0d623f7 195
6d2010ae
A
196#define IS_PM_ROOT (this == gIOPMRootNode)
197#define IS_ROOT_DOMAIN (getPMRootDomain() == this)
39236c6e
A
198#define IS_POWER_DROP (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState))
199#define IS_POWER_RISE (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState))
7e4a7d39
A
200
201// log setPowerStates longer than (ns):
202#define LOG_SETPOWER_TIMES (50ULL * 1000ULL * 1000ULL)
203// log app responses longer than (ns):
204#define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
205// use message tracer to log messages longer than (ns):
206#define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
207
7e4a7d39
A
208enum {
209 kReserveDomainPower = 1
210};
b0d623f7 211
6d2010ae
A
212#define MS_PUSH(n) \
213 do { assert(kIOPM_BadMachineState == fSavedMachineState); \
214 assert(kIOPM_BadMachineState != n); \
215 fSavedMachineState = n; } while (false)
216
217#define MS_POP() \
218 do { assert(kIOPM_BadMachineState != fSavedMachineState); \
219 fMachineState = fSavedMachineState; \
220 fSavedMachineState = kIOPM_BadMachineState; } while (false)
221
222#define PM_ACTION_0(a) \
223 do { if (fPMActions.a) { \
224 (fPMActions.a)(fPMActions.target, this, &fPMActions); } \
225 } while (false)
226
227#define PM_ACTION_2(a, x, y) \
228 do { if (fPMActions.a) { \
39236c6e
A
229 (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y, \
230 getPMRequestTag()); } \
231 } while (false)
232
233#define PM_ACTION_3(a, x, y, z) \
234 do { if (fPMActions.a) { \
235 (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y, z); } \
6d2010ae 236 } while (false)
39236c6e 237
316670eb
A
238static OSNumber * copyClientIDForNotification(
239 OSObject *object,
240 IOPMInterestContext *context);
241
242static void logClientIDForNotification(
243 OSObject *object,
244 IOPMInterestContext *context,
245 const char *logString);
6d2010ae 246
2d21ac55
A
247//*********************************************************************************
248// PM machine states
6d2010ae
A
249//
250// Check kgmacros after modifying machine states.
2d21ac55 251//*********************************************************************************
1c79356b 252
2d21ac55 253enum {
6d2010ae
A
254 kIOPM_Finished = 0,
255
2d21ac55 256 kIOPM_OurChangeTellClientsPowerDown = 1,
39236c6e
A
257 kIOPM_OurChangeTellUserPMPolicyPowerDown = 2,
258 kIOPM_OurChangeTellPriorityClientsPowerDown = 3,
259 kIOPM_OurChangeNotifyInterestedDriversWillChange = 4,
260 kIOPM_OurChangeSetPowerState = 5,
261 kIOPM_OurChangeWaitForPowerSettle = 6,
262 kIOPM_OurChangeNotifyInterestedDriversDidChange = 7,
263 kIOPM_OurChangeTellCapabilityDidChange = 8,
264 kIOPM_OurChangeFinish = 9,
6d2010ae
A
265
266 kIOPM_ParentChangeTellPriorityClientsPowerDown = 10,
267 kIOPM_ParentChangeNotifyInterestedDriversWillChange = 11,
268 kIOPM_ParentChangeSetPowerState = 12,
269 kIOPM_ParentChangeWaitForPowerSettle = 13,
270 kIOPM_ParentChangeNotifyInterestedDriversDidChange = 14,
271 kIOPM_ParentChangeTellCapabilityDidChange = 15,
272 kIOPM_ParentChangeAcknowledgePowerChange = 16,
273
274 kIOPM_NotifyChildrenStart = 17,
275 kIOPM_NotifyChildrenOrdered = 18,
276 kIOPM_NotifyChildrenDelayed = 19,
277 kIOPM_SyncTellClientsPowerDown = 20,
278 kIOPM_SyncTellPriorityClientsPowerDown = 21,
279 kIOPM_SyncNotifyWillChange = 22,
b0d623f7 280 kIOPM_SyncNotifyDidChange = 23,
6d2010ae
A
281 kIOPM_SyncTellCapabilityDidChange = 24,
282 kIOPM_SyncFinish = 25,
283 kIOPM_TellCapabilityChangeDone = 26,
284 kIOPM_DriverThreadCallDone = 27,
285
286 kIOPM_BadMachineState = 0xFFFFFFFF
2d21ac55
A
287};
288
2d21ac55 289//*********************************************************************************
b0d623f7 290// [public] PMinit
2d21ac55
A
291//
292// Initialize power management.
293//*********************************************************************************
1c79356b 294
39236c6e 295void IOService::PMinit( void )
1c79356b 296{
2d21ac55
A
297 if ( !initialized )
298 {
299 if ( !gIOPMInitialized )
300 {
b0d623f7 301 gPlatform = getPlatform();
6d2010ae
A
302 gIOPMWorkLoop = IOWorkLoop::workLoop();
303 if (gIOPMWorkLoop)
304 {
305 gIOPMRequestQueue = IOPMRequestQueue::create(
306 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
307 this, &IOService::servicePMRequestQueue));
308
309 gIOPMReplyQueue = IOPMRequestQueue::create(
310 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
311 this, &IOService::servicePMReplyQueue));
312
313 gIOPMWorkQueue = IOPMWorkQueue::create(
314 this,
315 OSMemberFunctionCast(IOPMWorkQueue::Action, this,
316 &IOService::servicePMRequest),
317 OSMemberFunctionCast(IOPMWorkQueue::Action, this,
318 &IOService::retirePMRequest));
319
320 gIOPMFreeQueue = IOPMCompletionQueue::create(
321 this, OSMemberFunctionCast(IOPMCompletionQueue::Action,
322 this, &IOService::servicePMFreeQueue));
323
324 if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
325 kIOReturnSuccess)
326 {
327 gIOPMRequestQueue->release();
328 gIOPMRequestQueue = 0;
329 }
2d21ac55 330
6d2010ae
A
331 if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
332 kIOReturnSuccess)
333 {
334 gIOPMReplyQueue->release();
335 gIOPMReplyQueue = 0;
336 }
337
338 if (gIOPMWorkLoop->addEventSource(gIOPMWorkQueue) !=
339 kIOReturnSuccess)
340 {
341 gIOPMWorkQueue->release();
342 gIOPMWorkQueue = 0;
343 }
2d21ac55 344
6d2010ae
A
345 if (gIOPMWorkLoop->addEventSource(gIOPMFreeQueue) !=
346 kIOReturnSuccess)
347 {
348 gIOPMFreeQueue->release();
349 gIOPMFreeQueue = 0;
350 }
2d21ac55 351
6d2010ae
A
352 gIOPMPowerClientDevice =
353 OSSymbol::withCStringNoCopy( "DevicePowerState" );
2d21ac55 354
6d2010ae
A
355 gIOPMPowerClientDriver =
356 OSSymbol::withCStringNoCopy( "DriverPowerState" );
2d21ac55 357
6d2010ae
A
358 gIOPMPowerClientChildProxy =
359 OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
b0d623f7 360
6d2010ae
A
361 gIOPMPowerClientChildren =
362 OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
db609669
A
363
364 gIOPMPowerClientAdvisoryTickle =
365 OSSymbol::withCStringNoCopy( "AdvisoryTicklePowerState" );
39236c6e
A
366
367 gIOPMPowerClientRootDomain =
368 OSSymbol::withCStringNoCopy( "RootDomainPower" );
6d2010ae 369 }
2d21ac55 370
6d2010ae
A
371 if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMFreeQueue)
372 gIOPMInitialized = true;
373 }
374 if (!gIOPMInitialized)
375 return;
2d21ac55
A
376
377 pwrMgt = new IOServicePM;
378 pwrMgt->init();
379 setProperty(kPwrMgtKey, pwrMgt);
380
6d2010ae
A
381 queue_init(&pwrMgt->WorkChain);
382 queue_init(&pwrMgt->RequestHead);
383 queue_init(&pwrMgt->PMDriverCallQueue);
384
385 fOwner = this;
2d21ac55
A
386 fPMLock = IOLockAlloc();
387 fInterestedDrivers = new IOPMinformeeList;
388 fInterestedDrivers->initialize();
39236c6e
A
389 fDesiredPowerState = kPowerStateZero;
390 fDeviceDesire = kPowerStateZero;
6d2010ae
A
391 fInitialPowerChange = true;
392 fInitialSetPowerState = true;
393 fPreviousRequestPowerFlags = 0;
394 fDeviceOverrideEnabled = false;
2d21ac55 395 fMachineState = kIOPM_Finished;
6d2010ae 396 fSavedMachineState = kIOPM_BadMachineState;
39236c6e 397 fIdleTimerMinPowerState = kPowerStateZero;
2d21ac55 398 fActivityLock = IOLockAlloc();
2d21ac55 399 fStrictTreeOrder = false;
db609669
A
400 fActivityTicklePowerState = kInvalidTicklePowerState;
401 fAdvisoryTicklePowerState = kInvalidTicklePowerState;
2d21ac55
A
402 fControllingDriver = NULL;
403 fPowerStates = NULL;
404 fNumberOfPowerStates = 0;
39236c6e 405 fCurrentPowerState = kPowerStateZero;
2d21ac55 406 fParentsCurrentPowerFlags = 0;
39236c6e 407 fMaxPowerState = kPowerStateZero;
2d21ac55 408 fName = getName();
2d21ac55
A
409 fParentsKnowState = false;
410 fSerialNumber = 0;
411 fResponseArray = NULL;
b0d623f7 412 fNotifyClientArray = NULL;
2d21ac55 413 fCurrentPowerConsumption = kIOPMUnknown;
b0d623f7 414 fOverrideMaxPowerState = kIOPMPowerStateMax;
2d21ac55 415
b0d623f7 416 if (!gIOPMRootNode && (getParentEntry(gIOPowerPlane) == getRegistryRoot()))
55e303ae 417 {
b0d623f7
A
418 gIOPMRootNode = this;
419 fParentsKnowState = true;
1c79356b 420 }
bd504ef0
A
421 else if (getProperty(kIOPMResetPowerStateOnWakeKey) == kOSBooleanTrue)
422 {
423 fResetPowerStateOnWake = true;
424 }
2d21ac55 425
39236c6e
A
426 if (IS_ROOT_DOMAIN)
427 {
428 fWatchdogTimer = thread_call_allocate(
429 &IOService::watchdog_timer_expired, (thread_call_param_t)this);
430 }
431
2d21ac55
A
432 fAckTimer = thread_call_allocate(
433 &IOService::ack_timer_expired, (thread_call_param_t)this);
434 fSettleTimer = thread_call_allocate(
435 &settle_timer_expired, (thread_call_param_t)this);
6d2010ae
A
436 fIdleTimer = thread_call_allocate(
437 &idle_timer_expired, (thread_call_param_t)this);
438 fDriverCallEntry = thread_call_allocate(
2d21ac55 439 (thread_call_func_t) &IOService::pmDriverCallout, this);
6d2010ae
A
440 assert(fDriverCallEntry);
441
442 // Check for powerChangeDone override.
443 if (OSMemberFunctionCast(void (*)(void),
444 getResourceService(), &IOService::powerChangeDone) !=
445 OSMemberFunctionCast(void (*)(void),
446 this, &IOService::powerChangeDone))
447 {
448 fPCDFunctionOverride = true;
449 }
2d21ac55
A
450
451#if PM_VARS_SUPPORT
452 IOPMprot * prot = new IOPMprot;
453 if (prot)
454 {
455 prot->init();
456 prot->ourName = fName;
b0d623f7 457 prot->thePlatform = gPlatform;
2d21ac55
A
458 fPMVars = prot;
459 pm_vars = prot;
460 }
461#else
6d2010ae 462 pm_vars = (void *) (uintptr_t) true;
2d21ac55
A
463#endif
464
1c79356b
A
465 initialized = true;
466 }
467}
468
0b4e3aa0 469//*********************************************************************************
b0d623f7 470// [private] PMfree
0b4e3aa0 471//
7e4a7d39 472// Free the data created by PMinit. Only called from IOService::free().
0b4e3aa0 473//*********************************************************************************
2d21ac55 474
39236c6e 475void IOService::PMfree( void )
0b4e3aa0 476{
6d2010ae 477 initialized = false;
2d21ac55
A
478 pm_vars = 0;
479
480 if ( pwrMgt )
6d2010ae
A
481 {
482 assert(fMachineState == kIOPM_Finished);
483 assert(fInsertInterestSet == NULL);
484 assert(fRemoveInterestSet == NULL);
2d21ac55 485 assert(fNotifyChildArray == NULL);
6d2010ae
A
486 assert(queue_empty(&pwrMgt->RequestHead));
487 assert(queue_empty(&fPMDriverCallQueue));
2d21ac55 488
39236c6e
A
489 if (fWatchdogTimer) {
490 thread_call_cancel(fWatchdogTimer);
491 thread_call_free(fWatchdogTimer);
492 fWatchdogTimer = NULL;
493 }
494
2d21ac55
A
495 if ( fSettleTimer ) {
496 thread_call_cancel(fSettleTimer);
497 thread_call_free(fSettleTimer);
498 fSettleTimer = NULL;
0b4e3aa0 499 }
2d21ac55
A
500 if ( fAckTimer ) {
501 thread_call_cancel(fAckTimer);
502 thread_call_free(fAckTimer);
503 fAckTimer = NULL;
0b4e3aa0 504 }
6d2010ae
A
505 if ( fIdleTimer ) {
506 thread_call_cancel(fIdleTimer);
507 thread_call_free(fIdleTimer);
508 fIdleTimer = NULL;
509 }
2d21ac55
A
510 if ( fDriverCallEntry ) {
511 thread_call_free(fDriverCallEntry);
512 fDriverCallEntry = NULL;
0b4e3aa0 513 }
2d21ac55
A
514 if ( fPMLock ) {
515 IOLockFree(fPMLock);
516 fPMLock = NULL;
0b4e3aa0 517 }
2d21ac55
A
518 if ( fActivityLock ) {
519 IOLockFree(fActivityLock);
520 fActivityLock = NULL;
0b4e3aa0 521 }
6d2010ae
A
522 if ( fInterestedDrivers ) {
523 fInterestedDrivers->release();
524 fInterestedDrivers = NULL;
525 }
526 if (fDriverCallParamSlots && fDriverCallParamPtr) {
527 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
528 fDriverCallParamPtr = 0;
529 fDriverCallParamSlots = 0;
530 }
2d21ac55
A
531 if ( fResponseArray ) {
532 fResponseArray->release();
533 fResponseArray = NULL;
0b4e3aa0 534 }
b0d623f7
A
535 if ( fNotifyClientArray ) {
536 fNotifyClientArray->release();
537 fNotifyClientArray = NULL;
538 }
2d21ac55 539 if (fPowerStates && fNumberOfPowerStates) {
6d2010ae 540 IODelete(fPowerStates, IOPMPSEntry, fNumberOfPowerStates);
2d21ac55
A
541 fNumberOfPowerStates = 0;
542 fPowerStates = NULL;
0b4e3aa0 543 }
6d2010ae
A
544 if (fPowerClients) {
545 fPowerClients->release();
546 fPowerClients = 0;
547 }
2d21ac55
A
548
549#if PM_VARS_SUPPORT
6d2010ae
A
550 if (fPMVars)
551 {
552 fPMVars->release();
553 fPMVars = 0;
554 }
2d21ac55
A
555#endif
556
557 pwrMgt->release();
6d2010ae 558 pwrMgt = 0;
0b4e3aa0
A
559 }
560}
561
4b17d6b6
A
562void IOService::PMDebug( uint32_t event, uintptr_t param1, uintptr_t param2 )
563{
564 OUR_PMLog(event, param1, param2);
565}
566
2d21ac55 567//*********************************************************************************
b0d623f7 568// [public] joinPMtree
2d21ac55
A
569//
570// A policy-maker calls its nub here when initializing, to be attached into
571// the power management hierarchy. The default function is to call the
572// platform expert, which knows how to do it. This method is overridden
573// by a nub subclass which may either know how to do it, or may need to
574// take other action.
575//
576// This may be the only "power management" method used in a nub,
577// meaning it may not be initialized for power management.
578//*********************************************************************************
579
39236c6e 580void IOService::joinPMtree( IOService * driver )
2d21ac55 581{
b0d623f7 582 IOPlatformExpert * platform;
2d21ac55
A
583
584 platform = getPlatform();
585 assert(platform != 0);
586 platform->PMRegisterDevice(this, driver);
587}
0b4e3aa0 588
b0d623f7 589#ifndef __LP64__
1c79356b 590//*********************************************************************************
b0d623f7 591// [deprecated] youAreRoot
1c79356b 592//
2d21ac55 593// Power Managment is informing us that we are the root power domain.
2d21ac55
A
594//*********************************************************************************
595
39236c6e 596IOReturn IOService::youAreRoot( void )
2d21ac55 597{
2d21ac55
A
598 return IOPMNoErr;
599}
b0d623f7 600#endif /* !__LP64__ */
2d21ac55
A
601
602//*********************************************************************************
b0d623f7 603// [public] PMstop
2d21ac55
A
604//
605// Immediately stop driver callouts. Schedule an async stop request to detach
606// from power plane.
1c79356b 607//*********************************************************************************
2d21ac55 608
39236c6e 609void IOService::PMstop( void )
1c79356b 610{
6d2010ae 611 IOPMRequest * request;
2d21ac55 612
6d2010ae
A
613 if (!initialized)
614 return;
2d21ac55 615
6d2010ae 616 PM_LOCK();
2d21ac55 617
6d2010ae 618 if (fLockedFlags.PMStop)
b0d623f7 619 {
6d2010ae
A
620 PM_LOG2("%s: PMstop() already stopped\n", fName);
621 PM_UNLOCK();
622 return;
b0d623f7 623 }
6d2010ae
A
624
625 // Inhibit future driver calls.
626 fLockedFlags.PMStop = true;
627
628 // Wait for all prior driver calls to finish.
629 waitForPMDriverCall();
630
2d21ac55
A
631 PM_UNLOCK();
632
6d2010ae
A
633 // The rest of the work is performed async.
634 request = acquirePMRequest( this, kIOPMRequestTypePMStop );
635 if (request)
636 {
39236c6e 637 PM_LOG2("%s: %p PMstop\n", getName(), OBFUSCATE(this));
6d2010ae
A
638 submitPMRequest( request );
639 }
2d21ac55
A
640}
641
642//*********************************************************************************
b0d623f7 643// [private] handlePMstop
2d21ac55 644//
b0d623f7 645// Disconnect the node from all parents and children in the power plane.
2d21ac55
A
646//*********************************************************************************
647
39236c6e 648void IOService::handlePMstop( IOPMRequest * request )
2d21ac55 649{
6d2010ae 650 OSIterator * iter;
2d21ac55 651 OSObject * next;
1c79356b 652 IOPowerConnection * connection;
2d21ac55
A
653 IOService * theChild;
654 IOService * theParent;
1c79356b 655
2d21ac55 656 PM_ASSERT_IN_GATE();
39236c6e 657 PM_LOG2("%s: %p %s start\n", getName(), OBFUSCATE(this), __FUNCTION__);
1c79356b 658
316670eb
A
659 // remove driver from prevent system sleep lists
660 getPMRootDomain()->updatePreventIdleSleepList(this, false);
661 getPMRootDomain()->updatePreventSystemSleepList(this, false);
662
2d21ac55
A
663 // remove the property
664 removeProperty(kPwrMgtKey);
665
666 // detach parents
667 iter = getParentIterator(gIOPowerPlane);
668 if ( iter )
55e303ae 669 {
2d21ac55 670 while ( (next = iter->getNextObject()) )
55e303ae 671 {
2d21ac55 672 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 673 {
0b4e3aa0 674 theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
2d21ac55 675 if ( theParent )
55e303ae 676 {
0b4e3aa0
A
677 theParent->removePowerChild(connection);
678 theParent->release();
679 }
1c79356b
A
680 }
681 }
682 iter->release();
683 }
55e303ae 684
2d21ac55
A
685 // detach IOConnections
686 detachAbove( gIOPowerPlane );
1c79356b 687
2d21ac55
A
688 // no more power state changes
689 fParentsKnowState = false;
1c79356b 690
2d21ac55
A
691 // detach children
692 iter = getChildIterator(gIOPowerPlane);
693 if ( iter )
55e303ae 694 {
2d21ac55 695 while ( (next = iter->getNextObject()) )
55e303ae 696 {
2d21ac55 697 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 698 {
0b4e3aa0 699 theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
2d21ac55 700 if ( theChild )
55e303ae
A
701 {
702 // detach nub from child
2d21ac55 703 connection->detachFromChild(theChild, gIOPowerPlane);
0b4e3aa0
A
704 theChild->release();
705 }
55e303ae 706 // detach us from nub
2d21ac55 707 detachFromChild(connection, gIOPowerPlane);
1c79356b
A
708 }
709 }
710 iter->release();
711 }
1c79356b 712
0b4e3aa0
A
713 // Remove all interested drivers from the list, including the power
714 // controlling driver.
715 //
716 // Usually, the controlling driver and the policy-maker functionality
717 // are implemented by the same object, and without the deregistration,
718 // the object will be holding an extra retain on itself, and cannot
719 // be freed.
720
2d21ac55 721 if ( fInterestedDrivers )
0b4e3aa0 722 {
6d2010ae 723 IOPMinformeeList * list = fInterestedDrivers;
2d21ac55 724 IOPMinformee * item;
1c79356b 725
6d2010ae
A
726 PM_LOCK();
727 while ((item = list->firstInList()))
728 {
729 list->removeFromList(item->whatObject);
730 }
731 PM_UNLOCK();
732 }
2d21ac55 733
bd504ef0
A
734 // Clear idle period to prevent idleTimerExpired() from servicing
735 // idle timer expirations.
736
6d2010ae
A
737 fIdleTimerPeriod = 0;
738 if (fIdleTimer && thread_call_cancel(fIdleTimer))
739 release();
1c79356b 740
39236c6e 741 PM_LOG2("%s: %p %s done\n", getName(), OBFUSCATE(this), __FUNCTION__);
2d21ac55 742}
1c79356b
A
743
744//*********************************************************************************
b0d623f7 745// [public] addPowerChild
1c79356b 746//
2d21ac55 747// Power Management is informing us who our children are.
1c79356b 748//*********************************************************************************
2d21ac55 749
39236c6e 750IOReturn IOService::addPowerChild( IOService * child )
1c79356b 751{
2d21ac55
A
752 IOPowerConnection * connection = 0;
753 IOPMRequest * requests[3] = {0, 0, 0};
754 OSIterator * iter;
755 bool ok = true;
756
757 if (!child)
758 return kIOReturnBadArgument;
759
760 if (!initialized || !child->initialized)
761 return IOPMNotYetInitialized;
762
b0d623f7 763 OUR_PMLog( kPMLogAddChild, (uintptr_t) child, 0 );
2d21ac55
A
764
765 do {
766 // Is this child already one of our children?
767
768 iter = child->getParentIterator( gIOPowerPlane );
769 if ( iter )
770 {
771 IORegistryEntry * entry;
772 OSObject * next;
773
774 while ((next = iter->getNextObject()))
775 {
776 if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
777 isChild(entry, gIOPowerPlane))
778 {
779 ok = false;
780 break;
781 }
782 }
783 iter->release();
784 }
785 if (!ok)
786 {
6d2010ae 787 PM_LOG("%s: %s (%p) is already a child\n",
39236c6e 788 getName(), child->getName(), OBFUSCATE(child));
2d21ac55
A
789 break;
790 }
791
792 // Add the child to the power plane immediately, but the
793 // joining connection is marked as not ready.
794 // We want the child to appear in the power plane before
795 // returning to the caller, but don't want the caller to
796 // block on the PM work loop.
797
798 connection = new IOPowerConnection;
799 if (!connection)
800 break;
801
802 // Create a chain of PM requests to perform the bottom-half
803 // work from the PM work loop.
804
805 requests[0] = acquirePMRequest(
806 /* target */ this,
807 /* type */ kIOPMRequestTypeAddPowerChild1 );
808
809 requests[1] = acquirePMRequest(
810 /* target */ child,
811 /* type */ kIOPMRequestTypeAddPowerChild2 );
812
813 requests[2] = acquirePMRequest(
814 /* target */ this,
815 /* type */ kIOPMRequestTypeAddPowerChild3 );
816
817 if (!requests[0] || !requests[1] || !requests[2])
818 break;
819
b0d623f7
A
820 requests[0]->attachNextRequest( requests[1] );
821 requests[1]->attachNextRequest( requests[2] );
2d21ac55
A
822
823 connection->init();
824 connection->start(this);
825 connection->setAwaitingAck(false);
826 connection->setReadyFlag(false);
827
828 attachToChild( connection, gIOPowerPlane );
829 connection->attachToChild( child, gIOPowerPlane );
830
831 // connection needs to be released
832 requests[0]->fArg0 = connection;
833 requests[1]->fArg0 = connection;
834 requests[2]->fArg0 = connection;
835
836 submitPMRequest( requests, 3 );
837 return kIOReturnSuccess;
838 }
839 while (false);
1c79356b 840
2d21ac55
A
841 if (connection) connection->release();
842 if (requests[0]) releasePMRequest(requests[0]);
843 if (requests[1]) releasePMRequest(requests[1]);
844 if (requests[2]) releasePMRequest(requests[2]);
1c79356b 845
b0d623f7 846 // Silent failure, to prevent platform drivers from adding the child
2d21ac55 847 // to the root domain.
b0d623f7
A
848
849 return kIOReturnSuccess;
2d21ac55 850}
1c79356b
A
851
852//*********************************************************************************
2d21ac55 853// [private] addPowerChild1
1c79356b 854//
b0d623f7 855// Step 1/3 of adding a power child. Called on the power parent.
1c79356b 856//*********************************************************************************
1c79356b 857
39236c6e 858void IOService::addPowerChild1( IOPMRequest * request )
2d21ac55 859{
39236c6e 860 IOPMPowerStateIndex tempDesire = kPowerStateZero;
2d21ac55
A
861
862 // Make us temporary usable before adding the child.
863
864 PM_ASSERT_IN_GATE();
b0d623f7 865 OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, 0 );
2d21ac55
A
866
867 if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
868 {
39236c6e 869 tempDesire = fHighestPowerState;
2d21ac55
A
870 }
871
39236c6e
A
872 if ((tempDesire != kPowerStateZero) &&
873 (IS_PM_ROOT || (StateOrder(fMaxPowerState) >= StateOrder(tempDesire))))
2d21ac55 874 {
b0d623f7 875 adjustPowerState(tempDesire);
2d21ac55
A
876 }
877}
1c79356b
A
878
879//*********************************************************************************
2d21ac55 880// [private] addPowerChild2
1c79356b 881//
b0d623f7
A
882// Step 2/3 of adding a power child. Called on the joining child.
883// Execution blocked behind addPowerChild1.
1c79356b 884//*********************************************************************************
2d21ac55 885
39236c6e 886void IOService::addPowerChild2( IOPMRequest * request )
1c79356b 887{
2d21ac55
A
888 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
889 IOService * parent;
890 IOPMPowerFlags powerFlags;
891 bool knowsState;
892 unsigned long powerState;
893 unsigned long tempDesire;
894
895 PM_ASSERT_IN_GATE();
896 parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
897
898 if (!parent || !inPlane(gIOPowerPlane))
899 {
6d2010ae 900 PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
2d21ac55
A
901 return;
902 }
1c79356b 903
b0d623f7
A
904 // Parent will be waiting for us to complete this stage.
905 // It is safe to directly access parent's vars.
0b4e3aa0 906
2d21ac55
A
907 knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
908 powerState = parent->fCurrentPowerState;
1c79356b 909
2d21ac55 910 if (knowsState)
6d2010ae 911 powerFlags = parent->fPowerStates[powerState].outputPowerFlags;
2d21ac55
A
912 else
913 powerFlags = 0;
1c79356b 914
2d21ac55
A
915 // Set our power parent.
916
917 OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
918
919 setParentInfo( powerFlags, connection, knowsState );
920
921 connection->setReadyFlag(true);
922
923 if ( fControllingDriver && fParentsKnowState )
55e303ae 924 {
6d2010ae 925 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
55e303ae 926 // initially change into the state we are already in
2d21ac55 927 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
6d2010ae 928 fPreviousRequestPowerFlags = (IOPMPowerFlags)(-1);
b0d623f7 929 adjustPowerState(tempDesire);
1c79356b 930 }
b0d623f7 931
6d2010ae 932 getPMRootDomain()->tagPowerPlaneService(this, &fPMActions);
1c79356b
A
933}
934
1c79356b 935//*********************************************************************************
2d21ac55 936// [private] addPowerChild3
1c79356b 937//
b0d623f7
A
938// Step 3/3 of adding a power child. Called on the parent.
939// Execution blocked behind addPowerChild2.
1c79356b 940//*********************************************************************************
1c79356b 941
39236c6e 942void IOService::addPowerChild3( IOPMRequest * request )
2d21ac55
A
943{
944 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
945 IOService * child;
b0d623f7 946 IOPMrootDomain * rootDomain = getPMRootDomain();
2d21ac55
A
947
948 PM_ASSERT_IN_GATE();
949 child = (IOService *) connection->getChildEntry(gIOPowerPlane);
950
951 if (child && inPlane(gIOPowerPlane))
952 {
440d4c6c 953 if ((this != rootDomain) && child->getProperty("IOPMStrictTreeOrder"))
2d21ac55 954 {
6d2010ae 955 PM_LOG1("%s: strict PM order enforced\n", getName());
2d21ac55
A
956 fStrictTreeOrder = true;
957 }
958
b0d623f7
A
959 if (rootDomain)
960 rootDomain->joinAggressiveness( child );
2d21ac55
A
961 }
962 else
963 {
6d2010ae 964 PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
2d21ac55 965 }
1c79356b 966
2d21ac55
A
967 connection->release();
968}
1c79356b 969
b0d623f7 970#ifndef __LP64__
2d21ac55 971//*********************************************************************************
b0d623f7 972// [deprecated] setPowerParent
2d21ac55
A
973//
974// Power Management is informing us who our parent is.
975// If we have a controlling driver, find out, given our newly-informed
976// power domain state, what state it would be in, and then tell it
977// to assume that state.
978//*********************************************************************************
1c79356b 979
39236c6e 980IOReturn IOService::setPowerParent(
2d21ac55
A
981 IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
982{
983 return kIOReturnUnsupported;
1c79356b 984}
b0d623f7 985#endif /* !__LP64__ */
1c79356b 986
2d21ac55 987//*********************************************************************************
b0d623f7 988// [public] removePowerChild
1c79356b 989//
2d21ac55
A
990// Called on a parent whose child is being removed by PMstop().
991//*********************************************************************************
992
39236c6e 993IOReturn IOService::removePowerChild( IOPowerConnection * theNub )
0b4e3aa0 994{
2d21ac55 995 IORegistryEntry * theChild;
0b4e3aa0 996
2d21ac55
A
997 PM_ASSERT_IN_GATE();
998 OUR_PMLog( kPMLogRemoveChild, 0, 0 );
1c79356b 999
0b4e3aa0 1000 theNub->retain();
b0d623f7 1001
55e303ae
A
1002 // detach nub from child
1003 theChild = theNub->copyChildEntry(gIOPowerPlane);
2d21ac55 1004 if ( theChild )
55e303ae 1005 {
0b4e3aa0
A
1006 theNub->detachFromChild(theChild, gIOPowerPlane);
1007 theChild->release();
1008 }
55e303ae 1009 // detach from the nub
2d21ac55
A
1010 detachFromChild(theNub, gIOPowerPlane);
1011
1012 // Are we awaiting an ack from this child?
1013 if ( theNub->getAwaitingAck() )
1014 {
1015 // yes, pretend we got one
1016 theNub->setAwaitingAck(false);
1017 if (fHeadNotePendingAcks != 0 )
1018 {
1019 // that's one fewer ack to worry about
1020 fHeadNotePendingAcks--;
1021
1022 // is that the last?
1023 if ( fHeadNotePendingAcks == 0 )
1024 {
1025 stop_ack_timer();
6d2010ae
A
1026
1027 // Request unblocked, work queue
1028 // should re-scan all busy requests.
1029 gIOPMWorkQueue->incrementProducerCount();
2d21ac55
A
1030 }
1031 }
1032 }
90556fb8 1033
2d21ac55 1034 theNub->release();
1c79356b 1035
b0d623f7
A
1036 // A child has gone away, re-scan children desires and clamp bits.
1037 // The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1038
1039 if (!fAdjustPowerScheduled)
2d21ac55
A
1040 {
1041 IOPMRequest * request;
2d21ac55
A
1042 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1043 if (request)
1044 {
1045 submitPMRequest( request );
b0d623f7 1046 fAdjustPowerScheduled = true;
2d21ac55
A
1047 }
1048 }
1c79356b
A
1049
1050 return IOPMNoErr;
1051}
1052
1c79356b 1053//*********************************************************************************
b0d623f7 1054// [public] registerPowerDriver
1c79356b
A
1055//
1056// A driver has called us volunteering to control power to our device.
1c79356b
A
1057//*********************************************************************************
1058
39236c6e 1059IOReturn IOService::registerPowerDriver(
2d21ac55
A
1060 IOService * powerDriver,
1061 IOPMPowerState * powerStates,
1062 unsigned long numberOfStates )
1c79356b 1063{
39236c6e
A
1064 IOPMRequest * request;
1065 IOPMPSEntry * powerStatesCopy = 0;
1066 IOPMPowerStateIndex stateOrder;
1067 IOReturn error = kIOReturnSuccess;
55e303ae 1068
2d21ac55
A
1069 if (!initialized)
1070 return IOPMNotYetInitialized;
1c79356b 1071
2d21ac55
A
1072 if (!powerStates || (numberOfStates < 2))
1073 {
1074 OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1075 return kIOReturnBadArgument;
1076 }
1c79356b 1077
b0d623f7 1078 if (!powerDriver || !powerDriver->initialized)
2d21ac55
A
1079 {
1080 OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1081 return kIOReturnBadArgument;
1082 }
1083
39236c6e 1084 if (powerStates[0].version > kIOPMPowerStateVersion2)
2d21ac55
A
1085 {
1086 OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1087 return kIOReturnBadArgument;
1088 }
1089
1090 do {
1091 // Make a copy of the supplied power state array.
6d2010ae 1092 powerStatesCopy = IONew(IOPMPSEntry, numberOfStates);
2d21ac55 1093 if (!powerStatesCopy)
39236c6e
A
1094 {
1095 error = kIOReturnNoMemory;
2d21ac55 1096 break;
39236c6e
A
1097 }
1098
1099 // Initialize to bogus values
1100 for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++)
1101 powerStatesCopy[i].stateOrderToIndex = kIOPMPowerStateMax;
2d21ac55 1102
6d2010ae
A
1103 for (uint32_t i = 0; i < numberOfStates; i++)
1104 {
1105 powerStatesCopy[i].capabilityFlags = powerStates[i].capabilityFlags;
1106 powerStatesCopy[i].outputPowerFlags = powerStates[i].outputPowerCharacter;
1107 powerStatesCopy[i].inputPowerFlags = powerStates[i].inputPowerRequirement;
1108 powerStatesCopy[i].staticPower = powerStates[i].staticPower;
1109 powerStatesCopy[i].settleUpTime = powerStates[i].settleUpTime;
1110 powerStatesCopy[i].settleDownTime = powerStates[i].settleDownTime;
39236c6e
A
1111 if (powerStates[i].version >= kIOPMPowerStateVersion2)
1112 stateOrder = powerStates[i].stateOrder;
1113 else
1114 stateOrder = i;
1115
1116 if (stateOrder < numberOfStates)
1117 {
1118 powerStatesCopy[i].stateOrder = stateOrder;
1119 powerStatesCopy[stateOrder].stateOrderToIndex = i;
1120 }
6d2010ae 1121 }
2d21ac55 1122
39236c6e
A
1123 for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++)
1124 {
1125 if (powerStatesCopy[i].stateOrderToIndex == kIOPMPowerStateMax)
1126 {
1127 // power state order missing
1128 error = kIOReturnBadArgument;
1129 break;
1130 }
1131 }
1132 if (kIOReturnSuccess != error)
1133 break;
1134
2d21ac55
A
1135 request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1136 if (!request)
39236c6e
A
1137 {
1138 error = kIOReturnNoMemory;
2d21ac55 1139 break;
39236c6e 1140 }
2d21ac55
A
1141
1142 powerDriver->retain();
1143 request->fArg0 = (void *) powerDriver;
1144 request->fArg1 = (void *) powerStatesCopy;
1145 request->fArg2 = (void *) numberOfStates;
1146
1147 submitPMRequest( request );
39236c6e 1148 return kIOReturnSuccess;
2d21ac55
A
1149 }
1150 while (false);
1151
1152 if (powerStatesCopy)
6d2010ae 1153 IODelete(powerStatesCopy, IOPMPSEntry, numberOfStates);
39236c6e
A
1154
1155 return error;
1c79356b
A
1156}
1157
1158//*********************************************************************************
2d21ac55
A
1159// [private] handleRegisterPowerDriver
1160//*********************************************************************************
1161
39236c6e 1162void IOService::handleRegisterPowerDriver( IOPMRequest * request )
2d21ac55 1163{
6d2010ae
A
1164 IOService * powerDriver = (IOService *) request->fArg0;
1165 IOPMPSEntry * powerStates = (IOPMPSEntry *) request->fArg1;
1166 unsigned long numberOfStates = (unsigned long) request->fArg2;
39236c6e
A
1167 unsigned long i, stateIndex;
1168 unsigned long lowestPowerState;
6d2010ae
A
1169 IOService * root;
1170 OSIterator * iter;
2d21ac55
A
1171
1172 PM_ASSERT_IN_GATE();
1173 assert(powerStates);
1174 assert(powerDriver);
1175 assert(numberOfStates > 1);
1176
1177 if ( !fNumberOfPowerStates )
1178 {
1179 OUR_PMLog(kPMLogControllingDriver,
1180 (unsigned long) numberOfStates,
6d2010ae 1181 (unsigned long) kIOPMPowerStateVersion1);
2d21ac55
A
1182
1183 fPowerStates = powerStates;
1184 fNumberOfPowerStates = numberOfStates;
1185 fControllingDriver = powerDriver;
1186 fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1187
39236c6e
A
1188 lowestPowerState = fPowerStates[0].stateOrderToIndex;
1189 fHighestPowerState = fPowerStates[numberOfStates - 1].stateOrderToIndex;
1190
1191 // OR'in all the output power flags
1192 fMergedOutputPowerFlags = 0;
1193 fDeviceUsablePowerState = lowestPowerState;
1194 for ( i = 0; i < numberOfStates; i++ )
1195 {
1196 fMergedOutputPowerFlags |= fPowerStates[i].outputPowerFlags;
1197
1198 stateIndex = fPowerStates[i].stateOrderToIndex;
1199 assert(stateIndex < numberOfStates);
1200 if ((fDeviceUsablePowerState == lowestPowerState) &&
1201 (fPowerStates[stateIndex].capabilityFlags & IOPMDeviceUsable))
db609669
A
1202 {
1203 // The minimum power state that the device is usable
39236c6e 1204 fDeviceUsablePowerState = stateIndex;
db609669 1205 }
2d21ac55 1206 }
39236c6e 1207
2d21ac55
A
1208 // Register powerDriver as interested, unless already done.
1209 // We don't want to register the default implementation since
1210 // it does nothing. One ramification of not always registering
1211 // is the one fewer retain count held.
1212
1213 root = getPlatform()->getProvider();
1214 assert(root);
1215 if (!root ||
1216 ((OSMemberFunctionCast(void (*)(void),
1217 root, &IOService::powerStateDidChangeTo)) !=
1218 ((OSMemberFunctionCast(void (*)(void),
1219 this, &IOService::powerStateDidChangeTo)))) ||
1220 ((OSMemberFunctionCast(void (*)(void),
1221 root, &IOService::powerStateWillChangeTo)) !=
1222 ((OSMemberFunctionCast(void (*)(void),
1223 this, &IOService::powerStateWillChangeTo)))))
1224 {
1225 if (fInterestedDrivers->findItem(powerDriver) == NULL)
1226 {
1227 PM_LOCK();
1228 fInterestedDrivers->appendNewInformee(powerDriver);
1229 PM_UNLOCK();
1230 }
1231 }
1232
b0d623f7
A
1233 // Examine all existing power clients and perform limit check.
1234
39236c6e
A
1235 if (fPowerClients &&
1236 (iter = OSCollectionIterator::withCollection(fPowerClients)))
b0d623f7 1237 {
39236c6e
A
1238 const OSSymbol * client;
1239 while ((client = (const OSSymbol *) iter->getNextObject()))
b0d623f7 1240 {
39236c6e
A
1241 IOPMPowerStateIndex powerState = getPowerStateForClient(client);
1242 if (powerState >= numberOfStates)
b0d623f7 1243 {
39236c6e 1244 updatePowerClient(client, fHighestPowerState);
b0d623f7 1245 }
b0d623f7 1246 }
39236c6e 1247 iter->release();
b0d623f7 1248 }
2d21ac55
A
1249
1250 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
1251 {
39236c6e 1252 IOPMPowerStateIndex tempDesire;
6d2010ae 1253 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
2d21ac55
A
1254 // initially change into the state we are already in
1255 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
b0d623f7 1256 adjustPowerState(tempDesire);
2d21ac55
A
1257 }
1258 }
1259 else
1260 {
1261 OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
6d2010ae 1262 IODelete(powerStates, IOPMPSEntry, numberOfStates);
2d21ac55
A
1263 }
1264
1265 powerDriver->release();
1266}
1267
1268//*********************************************************************************
b0d623f7 1269// [public] registerInterestedDriver
1c79356b
A
1270//
1271// Add the caller to our list of interested drivers and return our current
1272// power state. If we don't have a power-controlling driver yet, we will
1273// call this interested driver again later when we do get a driver and find
1274// out what the current power state of the device is.
1275//*********************************************************************************
1276
39236c6e 1277IOPMPowerFlags IOService::registerInterestedDriver( IOService * driver )
1c79356b 1278{
6d2010ae
A
1279 IOPMRequest * request;
1280 bool signal;
2d21ac55 1281
6d2010ae
A
1282 if (!driver || !initialized || !fInterestedDrivers)
1283 return 0;
2d21ac55 1284
6d2010ae
A
1285 PM_LOCK();
1286 signal = (!fInsertInterestSet && !fRemoveInterestSet);
1287 if (fInsertInterestSet == NULL)
1288 fInsertInterestSet = OSSet::withCapacity(4);
1289 if (fInsertInterestSet)
1290 {
1291 fInsertInterestSet->setObject(driver);
1292 if (fRemoveInterestSet)
1293 fRemoveInterestSet->removeObject(driver);
1294 }
1295 PM_UNLOCK();
2d21ac55 1296
6d2010ae
A
1297 if (signal)
1298 {
1299 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1300 if (request)
1301 submitPMRequest( request );
1302 }
1c79356b 1303
6d2010ae
A
1304 // This return value cannot be trusted, but return a value
1305 // for those clients that care.
1c79356b 1306
2d21ac55
A
1307 OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1308 return kIOPMDeviceUsable;
1309}
1c79356b 1310
2d21ac55 1311//*********************************************************************************
b0d623f7 1312// [public] deRegisterInterestedDriver
2d21ac55 1313//*********************************************************************************
1c79356b 1314
39236c6e 1315IOReturn IOService::deRegisterInterestedDriver( IOService * driver )
2d21ac55 1316{
6d2010ae 1317 IOPMinformeeList * list;
2d21ac55 1318 IOPMinformee * item;
6d2010ae
A
1319 IOPMRequest * request;
1320 bool signal;
2d21ac55 1321
6d2010ae
A
1322 if (!driver)
1323 return kIOReturnBadArgument;
1324 if (!initialized || !fInterestedDrivers)
1325 return IOPMNotPowerManaged;
2d21ac55 1326
6d2010ae
A
1327 PM_LOCK();
1328 signal = (!fRemoveInterestSet && !fInsertInterestSet);
1329 if (fRemoveInterestSet == NULL)
1330 fRemoveInterestSet = OSSet::withCapacity(4);
1331 if (fRemoveInterestSet)
1332 {
1333 fRemoveInterestSet->setObject(driver);
1334 if (fInsertInterestSet)
1335 fInsertInterestSet->removeObject(driver);
2d21ac55 1336
6d2010ae
A
1337 list = fInterestedDrivers;
1338 item = list->findItem(driver);
1339 if (item && item->active)
1340 {
1341 item->active = false;
1342 waitForPMDriverCall( driver );
1343 }
1344 }
1345 PM_UNLOCK();
1c79356b 1346
6d2010ae
A
1347 if (signal)
1348 {
1349 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1350 if (request)
1351 submitPMRequest( request );
1352 }
55e303ae 1353
6d2010ae 1354 return IOPMNoErr;
1c79356b
A
1355}
1356
1c79356b 1357//*********************************************************************************
2d21ac55 1358// [private] handleInterestChanged
1c79356b 1359//
2d21ac55 1360// Handle interest added or removed.
1c79356b 1361//*********************************************************************************
2d21ac55
A
1362
1363void IOService::handleInterestChanged( IOPMRequest * request )
1c79356b 1364{
6d2010ae 1365 IOService * driver;
2d21ac55 1366 IOPMinformee * informee;
6d2010ae 1367 IOPMinformeeList * list = fInterestedDrivers;
2d21ac55 1368
6d2010ae 1369 PM_LOCK();
2d21ac55 1370
6d2010ae
A
1371 if (fInsertInterestSet)
1372 {
1373 while ((driver = (IOService *) fInsertInterestSet->getAnyObject()))
1374 {
1375 if (list->findItem(driver) == NULL)
1376 {
1377 informee = list->appendNewInformee(driver);
1378 }
1379 fInsertInterestSet->removeObject(driver);
1380 }
1381 fInsertInterestSet->release();
1382 fInsertInterestSet = 0;
1383 }
1c79356b 1384
6d2010ae
A
1385 if (fRemoveInterestSet)
1386 {
1387 while ((driver = (IOService *) fRemoveInterestSet->getAnyObject()))
1388 {
1389 informee = list->findItem(driver);
1390 if (informee)
1391 {
1392 // Clean-up async interest acknowledgement
1393 if (fHeadNotePendingAcks && informee->timer)
1394 {
1395 informee->timer = 0;
1396 fHeadNotePendingAcks--;
1397 }
1398 list->removeFromList(driver);
1399 }
1400 fRemoveInterestSet->removeObject(driver);
1401 }
1402 fRemoveInterestSet->release();
1403 fRemoveInterestSet = 0;
1404 }
1c79356b 1405
6d2010ae 1406 PM_UNLOCK();
1c79356b
A
1407}
1408
1c79356b 1409//*********************************************************************************
b0d623f7 1410// [public] acknowledgePowerChange
1c79356b
A
1411//
1412// After we notified one of the interested drivers or a power-domain child
1413// of an impending change in power, it has called to say it is now
1414// prepared for the change. If this object is the last to
1415// acknowledge this change, we take whatever action we have been waiting
1416// for.
1417// That may include acknowledging to our parent. In this case, we do it
1418// last of all to insure that this doesn't cause the parent to call us some-
1419// where else and alter data we are relying on here (like the very existance
1420// of a "current change note".)
1421//*********************************************************************************
1422
39236c6e 1423IOReturn IOService::acknowledgePowerChange( IOService * whichObject )
1c79356b 1424{
2d21ac55
A
1425 IOPMRequest * request;
1426
1427 if (!initialized)
1428 return IOPMNotYetInitialized;
1429 if (!whichObject)
1430 return kIOReturnBadArgument;
1431
1432 request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1433 if (!request)
2d21ac55 1434 return kIOReturnNoMemory;
2d21ac55
A
1435
1436 whichObject->retain();
1437 request->fArg0 = whichObject;
1438
1439 submitPMRequest( request );
1440 return IOPMNoErr;
1441}
1442
1443//*********************************************************************************
1444// [private] handleAcknowledgePowerChange
1445//*********************************************************************************
1446
39236c6e 1447bool IOService::handleAcknowledgePowerChange( IOPMRequest * request )
2d21ac55
A
1448{
1449 IOPMinformee * informee;
1450 unsigned long childPower = kIOPMUnknown;
1451 IOService * theChild;
1452 IOService * whichObject;
1453 bool all_acked = false;
1454
1455 PM_ASSERT_IN_GATE();
1456 whichObject = (IOService *) request->fArg0;
1457 assert(whichObject);
1c79356b 1458
55e303ae 1459 // one of our interested drivers?
2d21ac55
A
1460 informee = fInterestedDrivers->findItem( whichObject );
1461 if ( informee == NULL )
55e303ae 1462 {
2d21ac55 1463 if ( !isChild(whichObject, gIOPowerPlane) )
55e303ae 1464 {
2d21ac55
A
1465 OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1466 goto no_err;
55e303ae 1467 } else {
2d21ac55 1468 OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
55e303ae
A
1469 }
1470 } else {
2d21ac55 1471 OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
55e303ae 1472 }
2d21ac55
A
1473
1474 if ( fHeadNotePendingAcks != 0 )
55e303ae 1475 {
2d21ac55
A
1476 assert(fPowerStates != NULL);
1477
55e303ae 1478 // yes, make sure we're expecting acks
2d21ac55 1479 if ( informee != NULL )
55e303ae
A
1480 {
1481 // it's an interested driver
1482 // make sure we're expecting this ack
2d21ac55 1483 if ( informee->timer != 0 )
55e303ae 1484 {
2d21ac55
A
1485#if LOG_SETPOWER_TIMES
1486 if (informee->timer > 0)
55e303ae 1487 {
2d21ac55
A
1488 uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1489 if (nsec > LOG_SETPOWER_TIMES)
6d2010ae 1490 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
2d21ac55
A
1491 informee->whatObject->getName(),
1492 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
39236c6e 1493 OBFUSCATE(informee->whatObject),
6d2010ae
A
1494 fName, fCurrentPowerState, fHeadNotePowerState, NS_TO_US(nsec));
1495
1496 uint16_t logType = (fDriverCallReason == kDriverCallInformPreChange)
1497 ? kIOPMEventTypePSWillChangeTo
1498 : kIOPMEventTypePSDidChangeTo;
1499
1500 PMEventDetails *details = PMEventDetails::eventDetails(
1501 logType,
1502 fName,
1503 (uintptr_t)this,
1504 informee->whatObject->getName(),
1505 0, 0, 0,
1506 NS_TO_MS(nsec));
1507
39236c6e 1508 getPMRootDomain()->recordAndReleasePMEvent( details );
55e303ae 1509 }
2d21ac55
A
1510#endif
1511 // mark it acked
1512 informee->timer = 0;
1513 // that's one fewer to worry about
1514 fHeadNotePendingAcks--;
55e303ae
A
1515 } else {
1516 // this driver has already acked
2d21ac55 1517 OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
55e303ae
A
1518 }
1519 } else {
1520 // it's a child
1521 // make sure we're expecting this ack
2d21ac55 1522 if ( ((IOPowerConnection *)whichObject)->getAwaitingAck() )
55e303ae
A
1523 {
1524 // that's one fewer to worry about
2d21ac55 1525 fHeadNotePendingAcks--;
0b4e3aa0
A
1526 ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1527 theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
2d21ac55 1528 if ( theChild )
55e303ae 1529 {
0b4e3aa0
A
1530 childPower = theChild->currentPowerConsumption();
1531 theChild->release();
1532 }
2d21ac55 1533 if ( childPower == kIOPMUnknown )
55e303ae 1534 {
b0d623f7 1535 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
55e303ae 1536 } else {
b0d623f7 1537 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown)
55e303ae 1538 {
b0d623f7 1539 fHeadNotePowerArrayEntry->staticPower += childPower;
0b4e3aa0
A
1540 }
1541 }
0b4e3aa0 1542 }
55e303ae 1543 }
2d21ac55
A
1544
1545 if ( fHeadNotePendingAcks == 0 ) {
1546 // yes, stop the timer
1547 stop_ack_timer();
1548 // and now we can continue
1549 all_acked = true;
1550 }
55e303ae 1551 } else {
2d21ac55 1552 OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1c79356b 1553 }
2d21ac55
A
1554
1555no_err:
1556 if (whichObject)
1557 whichObject->release();
1558
1559 return all_acked;
1c79356b
A
1560}
1561
1562//*********************************************************************************
b0d623f7 1563// [public] acknowledgeSetPowerState
1c79356b
A
1564//
1565// After we instructed our controlling driver to change power states,
1566// it has called to say it has finished doing so.
1567// We continue to process the power state change.
1568//*********************************************************************************
1569
39236c6e 1570IOReturn IOService::acknowledgeSetPowerState( void )
1c79356b 1571{
2d21ac55 1572 IOPMRequest * request;
9bccf70c 1573
2d21ac55
A
1574 if (!initialized)
1575 return IOPMNotYetInitialized;
91447636 1576
2d21ac55
A
1577 request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1578 if (!request)
2d21ac55 1579 return kIOReturnNoMemory;
1c79356b 1580
2d21ac55
A
1581 submitPMRequest( request );
1582 return kIOReturnSuccess;
1583}
1c79356b
A
1584
1585//*********************************************************************************
2d21ac55 1586// [private] adjustPowerState
1c79356b
A
1587//*********************************************************************************
1588
39236c6e 1589void IOService::adjustPowerState( uint32_t clamp )
1c79356b 1590{
2d21ac55 1591 PM_ASSERT_IN_GATE();
bd504ef0 1592 computeDesiredState(clamp, false);
b0d623f7 1593 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane))
2d21ac55 1594 {
6d2010ae
A
1595 IOPMPowerChangeFlags changeFlags = kIOPMSelfInitiated;
1596
bd504ef0 1597 // Indicate that children desires must be ignored, and do not ask
6d2010ae
A
1598 // apps for permission to drop power. This is used by root domain
1599 // for demand sleep.
1600
1601 if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)
1602 changeFlags |= (kIOPMIgnoreChildren | kIOPMSkipAskPowerDown);
1603
b0d623f7 1604 startPowerChange(
6d2010ae 1605 /* flags */ changeFlags,
b0d623f7
A
1606 /* power state */ fDesiredPowerState,
1607 /* domain flags */ 0,
1608 /* connection */ 0,
1609 /* parent flags */ 0);
2d21ac55 1610 }
b0d623f7
A
1611}
1612
1613//*********************************************************************************
1614// [public] synchronizePowerTree
1615//*********************************************************************************
1616
39236c6e 1617IOReturn IOService::synchronizePowerTree(
6d2010ae
A
1618 IOOptionBits options,
1619 IOService * notifyRoot )
b0d623f7 1620{
6d2010ae 1621 IOPMRequest * request_c = 0;
b0d623f7
A
1622 IOPMRequest * request_s;
1623
1624 if (this != getPMRootDomain())
1625 return kIOReturnBadArgument;
1626 if (!initialized)
1627 return kIOPMNotYetInitialized;
1628
39236c6e
A
1629 OUR_PMLog(kPMLogCSynchronizePowerTree, options, (notifyRoot != 0));
1630
6d2010ae
A
1631 if (notifyRoot)
1632 {
1633 IOPMRequest * nr;
b0d623f7 1634
6d2010ae
A
1635 // Cancels don't need to be synchronized.
1636 nr = acquirePMRequest(notifyRoot, kIOPMRequestTypeChildNotifyDelayCancel);
1637 if (nr) submitPMRequest(nr);
1638 nr = acquirePMRequest(getPMRootDomain(), kIOPMRequestTypeChildNotifyDelayCancel);
1639 if (nr) submitPMRequest(nr);
1640 }
b0d623f7 1641
6d2010ae
A
1642 request_s = acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree );
1643 if (!request_s)
1644 goto error_no_memory;
b0d623f7 1645
6d2010ae
A
1646 if (options & kIOPMSyncCancelPowerDown)
1647 request_c = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
1648 if (request_c)
1649 {
1650 request_c->attachNextRequest( request_s );
1651 submitPMRequest(request_c);
1652 }
1653
1654 request_s->fArg0 = (void *)(uintptr_t) options;
b0d623f7
A
1655 submitPMRequest(request_s);
1656
1657 return kIOReturnSuccess;
1658
1659error_no_memory:
1660 if (request_c) releasePMRequest(request_c);
1661 if (request_s) releasePMRequest(request_s);
1662 return kIOReturnNoMemory;
1663}
1664
1665//*********************************************************************************
1666// [private] handleSynchronizePowerTree
1667//*********************************************************************************
1668
39236c6e 1669void IOService::handleSynchronizePowerTree( IOPMRequest * request )
b0d623f7
A
1670{
1671 PM_ASSERT_IN_GATE();
1672 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane) &&
39236c6e 1673 (fCurrentPowerState == fHighestPowerState))
2d21ac55 1674 {
6d2010ae
A
1675 IOOptionBits options = (uintptr_t) request->fArg0;
1676
b0d623f7 1677 startPowerChange(
6d2010ae
A
1678 /* flags */ kIOPMSelfInitiated | kIOPMSynchronize |
1679 (options & kIOPMSyncNoChildNotify),
b0d623f7
A
1680 /* power state */ fCurrentPowerState,
1681 /* domain flags */ 0,
1682 /* connection */ 0,
1683 /* parent flags */ 0);
2d21ac55 1684 }
1c79356b
A
1685}
1686
b0d623f7 1687#ifndef __LP64__
1c79356b 1688//*********************************************************************************
b0d623f7 1689// [deprecated] powerDomainWillChangeTo
1c79356b
A
1690//
1691// Called by the power-hierarchy parent notifying of a new power state
1692// in the power domain.
1693// We enqueue a parent power-change to our queue of power changes.
1694// This may or may not cause us to change power, depending on what
1695// kind of change is occuring in the domain.
1696//*********************************************************************************
1697
39236c6e 1698IOReturn IOService::powerDomainWillChangeTo(
2d21ac55
A
1699 IOPMPowerFlags newPowerFlags,
1700 IOPowerConnection * whichParent )
1c79356b 1701{
2d21ac55
A
1702 assert(false);
1703 return kIOReturnUnsupported;
1704}
b0d623f7 1705#endif /* !__LP64__ */
1c79356b 1706
2d21ac55
A
1707//*********************************************************************************
1708// [private] handlePowerDomainWillChangeTo
1709//*********************************************************************************
1c79356b 1710
39236c6e 1711void IOService::handlePowerDomainWillChangeTo( IOPMRequest * request )
2d21ac55 1712{
6d2010ae
A
1713 IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1714 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1715 IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1716 IOPMPowerChangeFlags myChangeFlags;
1717 OSIterator * iter;
1718 OSObject * next;
1719 IOPowerConnection * connection;
bd504ef0 1720 IOPMPowerStateIndex maxPowerState;
6d2010ae
A
1721 IOPMPowerFlags combinedPowerFlags;
1722 bool savedParentsKnowState;
1723 IOReturn result = IOPMAckImplied;
2d21ac55
A
1724
1725 PM_ASSERT_IN_GATE();
b0d623f7 1726 OUR_PMLog(kPMLogWillChange, parentPowerFlags, 0);
2d21ac55 1727
cf7d32b8 1728 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
2d21ac55 1729 {
6d2010ae 1730 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
cf7d32b8 1731 goto exit_no_ack;
2d21ac55 1732 }
1c79356b 1733
2d21ac55 1734 savedParentsKnowState = fParentsKnowState;
0b4e3aa0 1735
b0d623f7
A
1736 // Combine parents' output power flags.
1737
2d21ac55 1738 combinedPowerFlags = 0;
1c79356b 1739
2d21ac55
A
1740 iter = getParentIterator(gIOPowerPlane);
1741 if ( iter )
55e303ae 1742 {
2d21ac55 1743 while ( (next = iter->getNextObject()) )
55e303ae 1744 {
2d21ac55 1745 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 1746 {
2d21ac55 1747 if ( connection == whichParent )
b0d623f7 1748 combinedPowerFlags |= parentPowerFlags;
2d21ac55 1749 else
1c79356b 1750 combinedPowerFlags |= connection->parentCurrentPowerFlags();
1c79356b
A
1751 }
1752 }
1753 iter->release();
1754 }
2d21ac55 1755
b0d623f7
A
1756 // If our initial change has yet to occur, then defer the power change
1757 // until after the power domain has completed its power transition.
1758
6d2010ae 1759 if ( fControllingDriver && !fInitialPowerChange )
55e303ae 1760 {
bd504ef0 1761 maxPowerState = fControllingDriver->maxCapabilityForDomainState(
2d21ac55
A
1762 combinedPowerFlags);
1763
bd504ef0
A
1764 // Use kIOPMSynchronize below instead of kIOPMRootBroadcastFlags
1765 // to avoid propagating the root change flags if any service must
1766 // change power state due to root's will-change notification.
1767 // Root does not change power state for kIOPMSynchronize.
1768
b0d623f7
A
1769 myChangeFlags = kIOPMParentInitiated | kIOPMDomainWillChange |
1770 (parentChangeFlags & kIOPMSynchronize);
1771
1772 result = startPowerChange(
1773 /* flags */ myChangeFlags,
bd504ef0 1774 /* power state */ maxPowerState,
b0d623f7 1775 /* domain flags */ combinedPowerFlags,
2d21ac55 1776 /* connection */ whichParent,
b0d623f7 1777 /* parent flags */ parentPowerFlags);
2d21ac55
A
1778 }
1779
1780 // If parent is dropping power, immediately update the parent's
1781 // capability flags. Any future merging of parent(s) combined
1782 // power flags should account for this power drop.
1783
b0d623f7 1784 if (parentChangeFlags & kIOPMDomainPowerDrop)
2d21ac55 1785 {
b0d623f7 1786 setParentInfo(parentPowerFlags, whichParent, true);
2d21ac55 1787 }
1c79356b 1788
2d21ac55 1789 // Parent is expecting an ACK from us. If we did not embark on a state
b0d623f7 1790 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
2d21ac55
A
1791 // still required to issue an ACK to our parent.
1792
1793 if (IOPMAckImplied == result)
1794 {
1795 IOService * parent;
1796 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1797 assert(parent);
1798 if ( parent )
1799 {
1800 parent->acknowledgePowerChange( whichParent );
1801 parent->release();
1802 }
1803 }
1804
cf7d32b8
A
1805exit_no_ack:
1806 // Drop the retain from notifyChild().
1807 if (whichParent) whichParent->release();
2d21ac55 1808}
1c79356b 1809
b0d623f7 1810#ifndef __LP64__
1c79356b 1811//*********************************************************************************
b0d623f7 1812// [deprecated] powerDomainDidChangeTo
1c79356b
A
1813//
1814// Called by the power-hierarchy parent after the power state of the power domain
1815// has settled at a new level.
1816// We enqueue a parent power-change to our queue of power changes.
1817// This may or may not cause us to change power, depending on what
1818// kind of change is occuring in the domain.
1819//*********************************************************************************
1820
39236c6e 1821IOReturn IOService::powerDomainDidChangeTo(
2d21ac55
A
1822 IOPMPowerFlags newPowerFlags,
1823 IOPowerConnection * whichParent )
1c79356b 1824{
2d21ac55
A
1825 assert(false);
1826 return kIOReturnUnsupported;
1827}
b0d623f7 1828#endif /* !__LP64__ */
1c79356b 1829
2d21ac55
A
1830//*********************************************************************************
1831// [private] handlePowerDomainDidChangeTo
1832//*********************************************************************************
1c79356b 1833
39236c6e 1834void IOService::handlePowerDomainDidChangeTo( IOPMRequest * request )
2d21ac55 1835{
6d2010ae
A
1836 IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1837 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1838 IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1839 IOPMPowerChangeFlags myChangeFlags;
bd504ef0 1840 IOPMPowerStateIndex maxPowerState;
39236c6e 1841 IOPMPowerStateIndex initialDesire = kPowerStateZero;
bd504ef0
A
1842 bool computeDesire = false;
1843 bool desireChanged = false;
6d2010ae
A
1844 bool savedParentsKnowState;
1845 IOReturn result = IOPMAckImplied;
2d21ac55
A
1846
1847 PM_ASSERT_IN_GATE();
b0d623f7 1848 OUR_PMLog(kPMLogDidChange, parentPowerFlags, 0);
2d21ac55 1849
cf7d32b8 1850 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
2d21ac55 1851 {
6d2010ae 1852 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
cf7d32b8 1853 goto exit_no_ack;
2d21ac55 1854 }
0b4e3aa0 1855
2d21ac55 1856 savedParentsKnowState = fParentsKnowState;
0b4e3aa0 1857
b0d623f7 1858 setParentInfo(parentPowerFlags, whichParent, true);
2d21ac55
A
1859
1860 if ( fControllingDriver )
1861 {
bd504ef0 1862 maxPowerState = fControllingDriver->maxCapabilityForDomainState(
2d21ac55
A
1863 fParentsCurrentPowerFlags);
1864
6d2010ae 1865 if (fInitialPowerChange)
b0d623f7 1866 {
bd504ef0 1867 computeDesire = true;
b0d623f7 1868 initialDesire = fControllingDriver->initialPowerStateForDomainState(
bd504ef0 1869 fParentsCurrentPowerFlags);
b0d623f7 1870 }
bd504ef0 1871 else if (parentChangeFlags & kIOPMRootChangeUp)
db609669 1872 {
bd504ef0
A
1873 if (fAdvisoryTickleUsed)
1874 {
1875 // On system wake, re-compute the desired power state since
1876 // gIOPMAdvisoryTickleEnabled will change for a full wake,
1877 // which is an input to computeDesiredState(). This is not
1878 // necessary for a dark wake because powerChangeDone() will
1879 // handle the dark to full wake case, but it does no harm.
1880
1881 desireChanged = true;
1882 }
1883
1884 if (fResetPowerStateOnWake)
1885 {
1886 // Query the driver for the desired power state on system wake.
1887 // Default implementation returns the lowest power state.
1888
1889 IOPMPowerStateIndex wakePowerState =
1890 fControllingDriver->initialPowerStateForDomainState(
1891 kIOPMRootDomainState | kIOPMPowerOn );
1892
1893 // fDesiredPowerState was adjusted before going to sleep
1894 // with fDeviceDesire at min.
1895
39236c6e 1896 if (StateOrder(wakePowerState) > StateOrder(fDesiredPowerState))
bd504ef0
A
1897 {
1898 // Must schedule a power adjustment if we changed the
1899 // device desire. That will update the desired domain
1900 // power on the parent power connection and ping the
1901 // power parent if necessary.
1902
1903 updatePowerClient(gIOPMPowerClientDevice, wakePowerState);
1904 desireChanged = true;
1905 }
1906 }
db609669 1907 }
b0d623f7 1908
bd504ef0
A
1909 if (computeDesire || desireChanged)
1910 computeDesiredState(initialDesire, false);
1911
1912 // Absorb and propagate parent's broadcast flags
b0d623f7 1913 myChangeFlags = kIOPMParentInitiated | kIOPMDomainDidChange |
bd504ef0 1914 (parentChangeFlags & kIOPMRootBroadcastFlags);
b0d623f7
A
1915
1916 result = startPowerChange(
1917 /* flags */ myChangeFlags,
bd504ef0 1918 /* power state */ maxPowerState,
b0d623f7 1919 /* domain flags */ fParentsCurrentPowerFlags,
2d21ac55 1920 /* connection */ whichParent,
b0d623f7 1921 /* parent flags */ 0);
2d21ac55 1922 }
0b4e3aa0 1923
2d21ac55 1924 // Parent is expecting an ACK from us. If we did not embark on a state
b0d623f7 1925 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
2d21ac55
A
1926 // still required to issue an ACK to our parent.
1927
1928 if (IOPMAckImplied == result)
1929 {
1930 IOService * parent;
1931 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1932 assert(parent);
1933 if ( parent )
1934 {
1935 parent->acknowledgePowerChange( whichParent );
1936 parent->release();
1937 }
1938 }
1939
b0d623f7 1940 // If the parent registers its power driver late, then this is the
bd504ef0
A
1941 // first opportunity to tell our parent about our desire. Or if the
1942 // child's desire changed during a parent change notify.
2d21ac55 1943
bd504ef0 1944 if ((!savedParentsKnowState && fParentsKnowState) || desireChanged)
2d21ac55 1945 {
bd504ef0
A
1946 PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState %d\n",
1947 getName(), fParentsKnowState);
7e4a7d39 1948 requestDomainPower( fDesiredPowerState );
2d21ac55 1949 }
cf7d32b8
A
1950
1951exit_no_ack:
1952 // Drop the retain from notifyChild().
1953 if (whichParent) whichParent->release();
2d21ac55 1954}
0b4e3aa0
A
1955
1956//*********************************************************************************
2d21ac55 1957// [private] setParentInfo
0b4e3aa0
A
1958//
1959// Set our connection data for one specific parent, and then combine all the parent
1960// data together.
1961//*********************************************************************************
2d21ac55 1962
39236c6e 1963void IOService::setParentInfo(
2d21ac55
A
1964 IOPMPowerFlags newPowerFlags,
1965 IOPowerConnection * whichParent,
1966 bool knowsState )
0b4e3aa0 1967{
2d21ac55
A
1968 OSIterator * iter;
1969 OSObject * next;
1970 IOPowerConnection * conn;
1c79356b 1971
2d21ac55
A
1972 PM_ASSERT_IN_GATE();
1973
1974 // set our connection data
1975 whichParent->setParentCurrentPowerFlags(newPowerFlags);
1976 whichParent->setParentKnowsState(knowsState);
0b4e3aa0 1977
55e303ae 1978 // recompute our parent info
2d21ac55
A
1979 fParentsCurrentPowerFlags = 0;
1980 fParentsKnowState = true;
1c79356b
A
1981
1982 iter = getParentIterator(gIOPowerPlane);
2d21ac55 1983 if ( iter )
55e303ae 1984 {
2d21ac55 1985 while ( (next = iter->getNextObject()) )
55e303ae 1986 {
2d21ac55 1987 if ( (conn = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 1988 {
2d21ac55
A
1989 fParentsKnowState &= conn->parentKnowsState();
1990 fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
1c79356b
A
1991 }
1992 }
1993 iter->release();
1994 }
1c79356b
A
1995}
1996
316670eb
A
1997//******************************************************************************
1998// [private] trackSystemSleepPreventers
1999//******************************************************************************
90556fb8 2000
316670eb
A
2001void IOService::trackSystemSleepPreventers(
2002 IOPMPowerStateIndex oldPowerState,
2003 IOPMPowerStateIndex newPowerState,
2004 IOPMPowerChangeFlags changeFlags __unused )
90556fb8 2005{
316670eb 2006 IOPMPowerFlags oldCapability, newCapability;
2d21ac55 2007
316670eb
A
2008 oldCapability = fPowerStates[oldPowerState].capabilityFlags &
2009 (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2010 newCapability = fPowerStates[newPowerState].capabilityFlags &
2011 (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
b0d623f7 2012
316670eb
A
2013 if (fHeadNoteChangeFlags & kIOPMInitialPowerChange)
2014 oldCapability = 0;
2015 if (oldCapability == newCapability)
2016 return;
90556fb8 2017
316670eb 2018 if ((oldCapability ^ newCapability) & kIOPMPreventIdleSleep)
90556fb8 2019 {
39236c6e
A
2020 bool idleCancelAllowed = getPMRootDomain()->updatePreventIdleSleepList(this,
2021 ((oldCapability & kIOPMPreventIdleSleep) == 0));
2022 if(!idleCancelAllowed)
2023 PM_LOG2("Idle cancel was disallowed for %s\n", getName());
316670eb 2024#if SUPPORT_IDLE_CANCEL
39236c6e 2025 if (idleCancelAllowed && (oldCapability & kIOPMPreventIdleSleep) == 0)
90556fb8 2026 {
316670eb 2027 IOPMRequest * cancelRequest;
2d21ac55 2028
bd504ef0 2029 cancelRequest = acquirePMRequest( getPMRootDomain(), kIOPMRequestTypeIdleCancel );
316670eb
A
2030 if (cancelRequest)
2031 {
bd504ef0 2032 submitPMRequest( cancelRequest );
90556fb8
A
2033 }
2034 }
316670eb
A
2035#endif
2036
316670eb
A
2037 }
2038
2039 if ((oldCapability ^ newCapability) & kIOPMPreventSystemSleep)
2040 {
2041
2042 getPMRootDomain()->updatePreventSystemSleepList(this,
2043 ((oldCapability & kIOPMPreventSystemSleep) == 0));
90556fb8 2044 }
90556fb8
A
2045}
2046
1c79356b 2047//*********************************************************************************
b0d623f7 2048// [public] requestPowerDomainState
1c79356b 2049//
7e4a7d39 2050// Called on a power parent when a child's power requirement changes.
1c79356b 2051//*********************************************************************************
2d21ac55 2052
7e4a7d39
A
2053IOReturn IOService::requestPowerDomainState(
2054 IOPMPowerFlags childRequestPowerFlags,
2055 IOPowerConnection * childConnection,
2056 unsigned long specification )
1c79356b 2057{
39236c6e 2058 IOPMPowerStateIndex order, powerState;
7e4a7d39
A
2059 IOPMPowerFlags outputPowerFlags;
2060 IOService * child;
2061 IOPMRequest * subRequest;
7e4a7d39 2062 bool adjustPower = false;
2d21ac55
A
2063
2064 if (!initialized)
2065 return IOPMNotYetInitialized;
2066
2067 if (gIOPMWorkLoop->onThread() == false)
2068 {
6d2010ae 2069 PM_LOG("%s::requestPowerDomainState\n", getName());
2d21ac55
A
2070 return kIOReturnSuccess;
2071 }
1c79356b 2072
7e4a7d39 2073 OUR_PMLog(kPMLogRequestDomain, childRequestPowerFlags, specification);
1c79356b 2074
7e4a7d39 2075 if (!isChild(childConnection, gIOPowerPlane))
2d21ac55
A
2076 return kIOReturnNotAttached;
2077
7e4a7d39 2078 if (!fControllingDriver || !fNumberOfPowerStates)
6d2010ae 2079 return kIOReturnNotReady;
2d21ac55 2080
7e4a7d39 2081 child = (IOService *) childConnection->getChildEntry(gIOPowerPlane);
2d21ac55 2082 assert(child);
1c79356b 2083
39236c6e
A
2084 // Remove flags from child request which we can't possibly supply
2085 childRequestPowerFlags &= fMergedOutputPowerFlags;
2086
7e4a7d39
A
2087 // Merge in the power flags contributed by this power parent
2088 // at its current or impending power state.
1c79356b 2089
6d2010ae 2090 outputPowerFlags = fPowerStates[fCurrentPowerState].outputPowerFlags;
060df5ea 2091 if (fMachineState != kIOPM_Finished)
7e4a7d39 2092 {
6d2010ae 2093 if (IS_POWER_DROP && !IS_ROOT_DOMAIN)
7e4a7d39 2094 {
39236c6e
A
2095 // Use the lower power state when dropping power.
2096 // Must be careful since a power drop can be cancelled
2097 // from the following states:
2098 // - kIOPM_OurChangeTellClientsPowerDown
2099 // - kIOPM_OurChangeTellPriorityClientsPowerDown
2100 //
2101 // The child must not wait for this parent to raise power
2102 // if the power drop was cancelled. The solution is to cancel
2103 // the power drop if possible, then schedule an adjustment to
2104 // re-evaluate the parent's power state.
2105 //
2106 // Root domain is excluded to avoid idle sleep issues. And allow
2107 // root domain children to pop up when system is going to sleep.
2108
2109 if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown) ||
2110 (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown))
2111 {
2112 fDoNotPowerDown = true; // cancel power drop
2113 adjustPower = true; // schedule an adjustment
2114 PM_LOG1("%s: power drop cancelled in state %u by %s\n",
2115 getName(), fMachineState, child->getName());
2116 }
7e4a7d39
A
2117 else
2118 {
2119 // Beyond cancellation point, report the impending state.
2120 outputPowerFlags =
6d2010ae 2121 fPowerStates[fHeadNotePowerState].outputPowerFlags;
7e4a7d39
A
2122 }
2123 }
060df5ea 2124 else if (IS_POWER_RISE)
7e4a7d39
A
2125 {
2126 // When raising power, must report the output power flags from
2127 // child's perspective. A child power request may arrive while
2128 // parent is transitioning upwards. If a request arrives after
2129 // setParentInfo() has already recorded the output power flags
2130 // for the next power state, then using the power supplied by
2131 // fCurrentPowerState is incorrect, and might cause the child
2132 // to wait when it should not.
2133
2134 outputPowerFlags = childConnection->parentCurrentPowerFlags();
2135 }
2136 }
2137 child->fHeadNoteDomainTargetFlags |= outputPowerFlags;
1c79356b 2138
7e4a7d39 2139 // Map child's requested power flags to one of our power state.
1c79356b 2140
39236c6e 2141 for (order = 0; order < fNumberOfPowerStates; order++)
7e4a7d39 2142 {
39236c6e
A
2143 powerState = fPowerStates[order].stateOrderToIndex;
2144 if ((fPowerStates[powerState].outputPowerFlags & childRequestPowerFlags)
2145 == childRequestPowerFlags)
7e4a7d39
A
2146 break;
2147 }
39236c6e 2148 if (order >= fNumberOfPowerStates)
7e4a7d39 2149 {
39236c6e 2150 powerState = kPowerStateZero;
1c79356b
A
2151 }
2152
7e4a7d39
A
2153 // Conditions that warrants a power adjustment on this parent.
2154 // Adjust power will also propagate any changes to the child's
2155 // prevent idle/sleep flags towards the root domain.
2156
2157 if (!childConnection->childHasRequestedPower() ||
39236c6e 2158 (powerState != childConnection->getDesiredDomainState()))
7e4a7d39
A
2159 adjustPower = true;
2160
2161#if ENABLE_DEBUG_LOGS
2162 if (adjustPower)
2163 {
6d2010ae 2164 PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
7e4a7d39
A
2165 getName(), child->getName(),
2166 !childConnection->childHasRequestedPower(),
2167 (uint32_t) childConnection->getDesiredDomainState(),
39236c6e 2168 (uint32_t) powerState);
7e4a7d39
A
2169 }
2170#endif
0b4e3aa0 2171
2d21ac55 2172 // Record the child's desires on the connection.
7e4a7d39 2173 childConnection->setChildHasRequestedPower();
39236c6e 2174 childConnection->setDesiredDomainState( powerState );
2d21ac55 2175
b0d623f7
A
2176 // Schedule a request to re-evaluate all children desires and
2177 // adjust power state. Submit a request if one wasn't pending,
2178 // or if the current request is part of a call tree.
2d21ac55 2179
6d2010ae 2180 if (adjustPower && !fDeviceOverrideEnabled &&
7e4a7d39 2181 (!fAdjustPowerScheduled || gIOPMRequest->getRootRequest()))
b0d623f7 2182 {
7e4a7d39
A
2183 subRequest = acquirePMRequest(
2184 this, kIOPMRequestTypeAdjustPowerState, gIOPMRequest );
2185 if (subRequest)
2d21ac55 2186 {
7e4a7d39 2187 submitPMRequest( subRequest );
b0d623f7 2188 fAdjustPowerScheduled = true;
2d21ac55 2189 }
7e4a7d39
A
2190 }
2191
7e4a7d39 2192 return kIOReturnSuccess;
2d21ac55 2193}
1c79356b
A
2194
2195//*********************************************************************************
b0d623f7 2196// [public] temporaryPowerClampOn
1c79356b
A
2197//
2198// A power domain wants to clamp its power on till it has children which
2199// will thendetermine the power domain state.
2200//
2201// We enter the highest state until addPowerChild is called.
2202//*********************************************************************************
2203
39236c6e 2204IOReturn IOService::temporaryPowerClampOn( void )
1c79356b 2205{
b0d623f7 2206 return requestPowerState( gIOPMPowerClientChildProxy, kIOPMPowerStateMax );
1c79356b
A
2207}
2208
1c79356b 2209//*********************************************************************************
b0d623f7 2210// [public] makeUsable
1c79356b
A
2211//
2212// Some client of our device is asking that we become usable. Although
2213// this has not come from a subclassed device object, treat it exactly
2214// as if it had. In this way, subsequent requests for lower power from
2215// a subclassed device object will pre-empt this request.
2216//
2217// We treat this as a subclass object request to switch to the
2218// highest power state.
2219//*********************************************************************************
2220
39236c6e 2221IOReturn IOService::makeUsable( void )
1c79356b 2222{
2d21ac55 2223 OUR_PMLog(kPMLogMakeUsable, 0, 0);
b0d623f7
A
2224 return requestPowerState( gIOPMPowerClientDevice, kIOPMPowerStateMax );
2225}
2d21ac55 2226
b0d623f7
A
2227//*********************************************************************************
2228// [public] currentCapability
2229//*********************************************************************************
2d21ac55 2230
39236c6e 2231IOPMPowerFlags IOService::currentCapability( void )
b0d623f7
A
2232{
2233 if (!initialized)
2234 return IOPMNotPowerManaged;
2235
2236 return fCurrentCapabilityFlags;
1c79356b
A
2237}
2238
2d21ac55 2239//*********************************************************************************
b0d623f7 2240// [public] changePowerStateTo
0c530ab8 2241//
b0d623f7
A
2242// Called by our power-controlling driver to change power state. The new desired
2243// power state is computed and compared against the current power state. If those
2244// power states differ, then a power state change is initiated.
2d21ac55 2245//*********************************************************************************
0c530ab8 2246
39236c6e 2247IOReturn IOService::changePowerStateTo( unsigned long ordinal )
0c530ab8 2248{
b0d623f7
A
2249 OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2250 return requestPowerState( gIOPMPowerClientDriver, ordinal );
0c530ab8
A
2251}
2252
1c79356b 2253//*********************************************************************************
b0d623f7
A
2254// [protected] changePowerStateToPriv
2255//
2256// Called by our driver subclass to change power state. The new desired power
2257// state is computed and compared against the current power state. If those
2258// power states differ, then a power state change is initiated.
1c79356b
A
2259//*********************************************************************************
2260
39236c6e 2261IOReturn IOService::changePowerStateToPriv( unsigned long ordinal )
1c79356b 2262{
b0d623f7
A
2263 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2264 return requestPowerState( gIOPMPowerClientDevice, ordinal );
2d21ac55 2265}
1c79356b
A
2266
2267//*********************************************************************************
39236c6e 2268// [public] changePowerStateWithOverrideTo
1c79356b 2269//
b0d623f7
A
2270// Called by our driver subclass to change power state. The new desired power
2271// state is computed and compared against the current power state. If those
2272// power states differ, then a power state change is initiated.
2273// Override enforced - Children and Driver desires are ignored.
1c79356b
A
2274//*********************************************************************************
2275
39236c6e
A
2276IOReturn IOService::changePowerStateWithOverrideTo( IOPMPowerStateIndex ordinal,
2277 IOPMRequestTag tag )
1c79356b 2278{
2d21ac55 2279 IOPMRequest * request;
1c79356b 2280
2d21ac55 2281 if (!initialized)
b0d623f7 2282 return kIOPMNotYetInitialized;
2d21ac55 2283
b0d623f7 2284 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2d21ac55 2285
b0d623f7 2286 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride );
2d21ac55
A
2287 if (!request)
2288 return kIOReturnNoMemory;
2289
b0d623f7 2290 gIOPMPowerClientDevice->retain();
39236c6e 2291 request->fRequestTag = tag;
b0d623f7
A
2292 request->fArg0 = (void *) ordinal;
2293 request->fArg1 = (void *) gIOPMPowerClientDevice;
2294 request->fArg2 = 0;
2295#if NOT_READY
2296 if (action)
2297 request->installCompletionAction( action, target, param );
2298#endif
1c79356b 2299
b0d623f7
A
2300 // Prevent needless downwards power transitions by clamping power
2301 // until the scheduled request is executed.
2d21ac55 2302
b0d623f7 2303 if (gIOPMWorkLoop->inGate() && (ordinal < fNumberOfPowerStates))
2d21ac55 2304 {
39236c6e 2305 fTempClampPowerState = StateMax(fTempClampPowerState, ordinal);
2d21ac55 2306 fTempClampCount++;
6d2010ae
A
2307 fOverrideMaxPowerState = ordinal;
2308 request->fArg2 = (void *) (uintptr_t) true;
2d21ac55
A
2309 }
2310
2311 submitPMRequest( request );
1c79356b
A
2312 return IOPMNoErr;
2313}
2314
39236c6e
A
2315//*********************************************************************************
2316// [public] changePowerStateForRootDomain
2317//
2318// Adjust the root domain's power desire on the target
2319//*********************************************************************************
2320
2321IOReturn IOService::changePowerStateForRootDomain( IOPMPowerStateIndex ordinal )
2322{
2323 OUR_PMLog(kPMLogChangeStateForRootDomain, ordinal, 0);
2324 return requestPowerState( gIOPMPowerClientRootDomain, ordinal );
2325}
2326
1c79356b 2327//*********************************************************************************
b0d623f7 2328// [private] requestPowerState
1c79356b
A
2329//*********************************************************************************
2330
39236c6e 2331IOReturn IOService::requestPowerState(
b0d623f7
A
2332 const OSSymbol * client,
2333 uint32_t state )
1c79356b 2334{
2d21ac55 2335 IOPMRequest * request;
1c79356b 2336
b0d623f7
A
2337 if (!client)
2338 return kIOReturnBadArgument;
2d21ac55 2339 if (!initialized)
b0d623f7 2340 return kIOPMNotYetInitialized;
2d21ac55 2341
b0d623f7 2342 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerState );
2d21ac55
A
2343 if (!request)
2344 return kIOReturnNoMemory;
2345
b0d623f7 2346 client->retain();
39236c6e
A
2347 request->fArg0 = (void *)(uintptr_t) state;
2348 request->fArg1 = (void *) client;
b0d623f7
A
2349 request->fArg2 = 0;
2350#if NOT_READY
2351 if (action)
2352 request->installCompletionAction( action, target, param );
2353#endif
2d21ac55 2354
b0d623f7
A
2355 // Prevent needless downwards power transitions by clamping power
2356 // until the scheduled request is executed.
2d21ac55 2357
b0d623f7 2358 if (gIOPMWorkLoop->inGate() && (state < fNumberOfPowerStates))
2d21ac55 2359 {
39236c6e 2360 fTempClampPowerState = StateMax(fTempClampPowerState, state);
2d21ac55 2361 fTempClampCount++;
6d2010ae 2362 request->fArg2 = (void *) (uintptr_t) true;
2d21ac55 2363 }
1c79356b 2364
2d21ac55 2365 submitPMRequest( request );
1c79356b
A
2366 return IOPMNoErr;
2367}
2368
2d21ac55 2369//*********************************************************************************
b0d623f7 2370// [private] handleRequestPowerState
2d21ac55
A
2371//*********************************************************************************
2372
39236c6e 2373void IOService::handleRequestPowerState( IOPMRequest * request )
2d21ac55 2374{
b0d623f7
A
2375 const OSSymbol * client = (const OSSymbol *) request->fArg1;
2376 uint32_t state = (uint32_t)(uintptr_t) request->fArg0;
2d21ac55
A
2377
2378 PM_ASSERT_IN_GATE();
b0d623f7 2379 if (request->fArg2)
2d21ac55
A
2380 {
2381 assert(fTempClampCount != 0);
b0d623f7 2382 if (fTempClampCount) fTempClampCount--;
39236c6e 2383 if (!fTempClampCount) fTempClampPowerState = kPowerStateZero;
2d21ac55
A
2384 }
2385
b0d623f7 2386 if (fNumberOfPowerStates && (state >= fNumberOfPowerStates))
39236c6e 2387 state = fHighestPowerState;
b0d623f7 2388
6d2010ae
A
2389 // The power suppression due to changePowerStateWithOverrideTo() expires
2390 // upon the next "device" power request - changePowerStateToPriv().
b0d623f7
A
2391
2392 if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride) &&
2393 (client == gIOPMPowerClientDevice))
2394 fOverrideMaxPowerState = kIOPMPowerStateMax;
2395
39236c6e 2396 if ((state == kPowerStateZero) &&
b0d623f7
A
2397 (client != gIOPMPowerClientDevice) &&
2398 (client != gIOPMPowerClientDriver) &&
2399 (client != gIOPMPowerClientChildProxy))
2400 removePowerClient(client);
2401 else
2402 updatePowerClient(client, state);
2403
2404 adjustPowerState();
2405 client->release();
2406}
2407
2408//*********************************************************************************
2409// [private] Helper functions to update/remove power clients.
2410//*********************************************************************************
2411
2412void IOService::updatePowerClient( const OSSymbol * client, uint32_t powerState )
2413{
39236c6e
A
2414 IOPMPowerStateIndex oldPowerState = kPowerStateZero;
2415
b0d623f7
A
2416 if (!fPowerClients)
2417 fPowerClients = OSDictionary::withCapacity(4);
2418 if (fPowerClients && client)
2419 {
2420 OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2421 if (num)
39236c6e
A
2422 {
2423 oldPowerState = num->unsigned32BitValue();
b0d623f7 2424 num->setValue(powerState);
39236c6e 2425 }
b0d623f7
A
2426 else
2427 {
2428 num = OSNumber::withNumber(powerState, 32);
2429 if (num)
2430 {
2431 fPowerClients->setObject(client, num);
2432 num->release();
2433 }
2434 }
39236c6e
A
2435
2436 PM_ACTION_3(actionUpdatePowerClient, client, oldPowerState, powerState);
b0d623f7
A
2437 }
2438}
2439
2440void IOService::removePowerClient( const OSSymbol * client )
2441{
2442 if (fPowerClients && client)
2443 fPowerClients->removeObject(client);
2444}
2445
2446uint32_t IOService::getPowerStateForClient( const OSSymbol * client )
2447{
39236c6e 2448 uint32_t powerState = kPowerStateZero;
b0d623f7
A
2449
2450 if (fPowerClients && client)
2451 {
2452 OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2453 if (num) powerState = num->unsigned32BitValue();
2454 }
2455 return powerState;
2d21ac55 2456}
1c79356b 2457
6d2010ae
A
2458//*********************************************************************************
2459// [protected] powerOverrideOnPriv
2460//*********************************************************************************
2461
39236c6e 2462IOReturn IOService::powerOverrideOnPriv( void )
6d2010ae
A
2463{
2464 IOPMRequest * request;
2465
2466 if (!initialized)
2467 return IOPMNotYetInitialized;
2468
2469 if (gIOPMWorkLoop->inGate())
2470 {
2471 fDeviceOverrideEnabled = true;
2472 return IOPMNoErr;
2473 }
2474
2475 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2476 if (!request)
2477 return kIOReturnNoMemory;
2478
2479 submitPMRequest( request );
2480 return IOPMNoErr;
2481}
2482
2483//*********************************************************************************
2484// [protected] powerOverrideOffPriv
2485//*********************************************************************************
2486
39236c6e 2487IOReturn IOService::powerOverrideOffPriv( void )
6d2010ae
A
2488{
2489 IOPMRequest * request;
2490
2491 if (!initialized)
2492 return IOPMNotYetInitialized;
2493
2494 if (gIOPMWorkLoop->inGate())
2495 {
2496 fDeviceOverrideEnabled = false;
2497 return IOPMNoErr;
2498 }
2499
2500 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2501 if (!request)
2502 return kIOReturnNoMemory;
2503
2504 submitPMRequest( request );
2505 return IOPMNoErr;
2506}
2507
2508//*********************************************************************************
2509// [private] handlePowerOverrideChanged
2510//*********************************************************************************
2511
39236c6e 2512void IOService::handlePowerOverrideChanged( IOPMRequest * request )
6d2010ae
A
2513{
2514 PM_ASSERT_IN_GATE();
2515 if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv)
2516 {
2517 OUR_PMLog(kPMLogOverrideOn, 0, 0);
2518 fDeviceOverrideEnabled = true;
2519 }
2520 else
2521 {
2522 OUR_PMLog(kPMLogOverrideOff, 0, 0);
2523 fDeviceOverrideEnabled = false;
2524 }
2525
2526 adjustPowerState();
2527}
2528
1c79356b 2529//*********************************************************************************
2d21ac55 2530// [private] computeDesiredState
1c79356b
A
2531//*********************************************************************************
2532
bd504ef0 2533void IOService::computeDesiredState( unsigned long localClamp, bool computeOnly )
1c79356b 2534{
2d21ac55
A
2535 OSIterator * iter;
2536 OSObject * next;
2537 IOPowerConnection * connection;
39236c6e
A
2538 uint32_t desiredState = kPowerStateZero;
2539 uint32_t newPowerState = kPowerStateZero;
b0d623f7 2540 bool hasChildren = false;
2d21ac55 2541
b0d623f7 2542 // Desired power state is always 0 without a controlling driver.
2d21ac55 2543
b0d623f7
A
2544 if (!fNumberOfPowerStates)
2545 {
39236c6e 2546 fDesiredPowerState = kPowerStateZero;
b0d623f7
A
2547 return;
2548 }
2d21ac55 2549
b0d623f7 2550 // Examine the children's desired power state.
1c79356b 2551
b0d623f7
A
2552 iter = getChildIterator(gIOPowerPlane);
2553 if (iter)
55e303ae 2554 {
b0d623f7 2555 while ((next = iter->getNextObject()))
55e303ae 2556 {
b0d623f7 2557 if ((connection = OSDynamicCast(IOPowerConnection, next)))
55e303ae 2558 {
b0d623f7 2559 if (connection->getReadyFlag() == false)
55e303ae 2560 {
6d2010ae 2561 PM_LOG3("[%s] %s: connection not ready\n",
b0d623f7
A
2562 getName(), __FUNCTION__);
2563 continue;
1c79356b 2564 }
b0d623f7
A
2565 if (connection->childHasRequestedPower())
2566 hasChildren = true;
39236c6e 2567 desiredState = StateMax(connection->getDesiredDomainState(), desiredState);
1c79356b 2568 }
1c79356b 2569 }
b0d623f7
A
2570 iter->release();
2571 }
2572 if (hasChildren)
2573 updatePowerClient(gIOPMPowerClientChildren, desiredState);
2574 else
2575 removePowerClient(gIOPMPowerClientChildren);
2d21ac55 2576
b0d623f7
A
2577 // Iterate through all power clients to determine the min power state.
2578
2579 iter = OSCollectionIterator::withCollection(fPowerClients);
2580 if (iter)
2581 {
2582 const OSSymbol * client;
2583 while ((client = (const OSSymbol *) iter->getNextObject()))
2584 {
2585 // Ignore child and driver when override is in effect.
6d2010ae 2586 if ((fDeviceOverrideEnabled ||
b0d623f7
A
2587 (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)) &&
2588 ((client == gIOPMPowerClientChildren) ||
2589 (client == gIOPMPowerClientDriver)))
2590 continue;
2591
2592 // Ignore child proxy when children are present.
2593 if (hasChildren && (client == gIOPMPowerClientChildProxy))
2594 continue;
2595
bd504ef0 2596 // Advisory tickles are irrelevant unless system is in full wake
db609669
A
2597 if (client == gIOPMPowerClientAdvisoryTickle &&
2598 !gIOPMAdvisoryTickleEnabled)
2599 continue;
2600
b0d623f7
A
2601 desiredState = getPowerStateForClient(client);
2602 assert(desiredState < fNumberOfPowerStates);
6d2010ae 2603 PM_LOG1(" %u %s\n",
b0d623f7
A
2604 desiredState, client->getCStringNoCopy());
2605
39236c6e 2606 newPowerState = StateMax(newPowerState, desiredState);
b0d623f7
A
2607
2608 if (client == gIOPMPowerClientDevice)
2609 fDeviceDesire = desiredState;
2610 }
2611 iter->release();
1c79356b
A
2612 }
2613
b0d623f7
A
2614 // Factor in the temporary power desires.
2615
39236c6e
A
2616 newPowerState = StateMax(newPowerState, localClamp);
2617 newPowerState = StateMax(newPowerState, fTempClampPowerState);
b0d623f7
A
2618
2619 // Limit check against max power override.
2620
39236c6e 2621 newPowerState = StateMin(newPowerState, fOverrideMaxPowerState);
2d21ac55 2622
2d21ac55
A
2623 // Limit check against number of power states.
2624
b0d623f7 2625 if (newPowerState >= fNumberOfPowerStates)
39236c6e 2626 newPowerState = fHighestPowerState;
b0d623f7
A
2627
2628 fDesiredPowerState = newPowerState;
2629
6d2010ae 2630 PM_LOG1(" temp %u, clamp %u, current %u, new %u\n",
b0d623f7
A
2631 (uint32_t) localClamp, (uint32_t) fTempClampPowerState,
2632 (uint32_t) fCurrentPowerState, newPowerState);
1c79356b 2633
bd504ef0 2634 if (!computeOnly)
db609669 2635 {
bd504ef0
A
2636 // Restart idle timer if possible when device desire has increased.
2637 // Or if an advisory desire exists.
2638
2639 if (fIdleTimerPeriod && fIdleTimerStopped)
db609669 2640 {
bd504ef0 2641 restartIdleTimer();
db609669 2642 }
2d21ac55 2643
bd504ef0
A
2644 // Invalidate cached tickle power state when desires change, and not
2645 // due to a tickle request. In case the driver has requested a lower
2646 // power state, but the tickle is caching a higher power state which
2647 // will drop future tickles until the cached value is lowered or in-
2648 // validated. The invalidation must occur before the power transition
2649 // to avoid dropping a necessary tickle.
2d21ac55 2650
bd504ef0
A
2651 if ((getPMRequestType() != kIOPMRequestTypeActivityTickle) &&
2652 (fActivityTicklePowerState != kInvalidTicklePowerState))
2653 {
2654 IOLockLock(fActivityLock);
2655 fActivityTicklePowerState = kInvalidTicklePowerState;
2656 IOLockUnlock(fActivityLock);
2657 }
db609669 2658 }
2d21ac55 2659}
1c79356b
A
2660
2661//*********************************************************************************
b0d623f7 2662// [public] currentPowerConsumption
1c79356b
A
2663//
2664//*********************************************************************************
2665
39236c6e 2666unsigned long IOService::currentPowerConsumption( void )
1c79356b 2667{
2d21ac55 2668 if (!initialized)
0b4e3aa0 2669 return kIOPMUnknown;
2d21ac55
A
2670
2671 return fCurrentPowerConsumption;
2672}
2673
2674//*********************************************************************************
b0d623f7 2675// [deprecated] getPMworkloop
2d21ac55
A
2676//*********************************************************************************
2677
39236c6e 2678IOWorkLoop * IOService::getPMworkloop( void )
2d21ac55
A
2679{
2680 return gIOPMWorkLoop;
1c79356b
A
2681}
2682
6d2010ae
A
2683#if NOT_YET
2684
1c79356b 2685//*********************************************************************************
6d2010ae
A
2686// Power Parent/Children Applier
2687//*********************************************************************************
2688
2689static void
2690applyToPowerChildren(
2691 IOService * service,
2692 IOServiceApplierFunction applier,
2693 void * context,
2694 IOOptionBits options )
2695{
2696 PM_ASSERT_IN_GATE();
2697
2698 IORegistryEntry * entry;
2699 IORegistryIterator * iter;
2700 IOPowerConnection * connection;
2701 IOService * child;
2702
2703 iter = IORegistryIterator::iterateOver(service, gIOPowerPlane, options);
2704 if (iter)
2705 {
2706 while ((entry = iter->getNextObject()))
2707 {
2708 // Get child of IOPowerConnection objects
2709 if ((connection = OSDynamicCast(IOPowerConnection, entry)))
2710 {
2711 child = (IOService *) connection->copyChildEntry(gIOPowerPlane);
2712 if (child)
2713 {
2714 (*applier)(child, context);
2715 child->release();
2716 }
2717 }
2718 }
2719 iter->release();
2720 }
2721}
2722
2723static void
2724applyToPowerParent(
2725 IOService * service,
2726 IOServiceApplierFunction applier,
2727 void * context,
2728 IOOptionBits options )
2729{
2730 PM_ASSERT_IN_GATE();
2731
2732 IORegistryEntry * entry;
2733 IORegistryIterator * iter;
2734 IOPowerConnection * connection;
2735 IOService * parent;
2736
2737 iter = IORegistryIterator::iterateOver(service, gIOPowerPlane,
2738 options | kIORegistryIterateParents);
2739 if (iter)
2740 {
2741 while ((entry = iter->getNextObject()))
2742 {
2743 // Get child of IOPowerConnection objects
2744 if ((connection = OSDynamicCast(IOPowerConnection, entry)))
2745 {
2746 parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
2747 if (parent)
2748 {
2749 (*applier)(parent, context);
2750 parent->release();
2751 }
2752 }
2753 }
2754 iter->release();
2755 }
2756}
2757
2758#endif /* NOT_YET */
2759
2760// MARK: -
2761// MARK: Activity Tickle & Idle Timer
2762
db609669
A
2763void IOService::setAdvisoryTickleEnable( bool enable )
2764{
2765 gIOPMAdvisoryTickleEnabled = enable;
2766}
2767
6d2010ae
A
2768//*********************************************************************************
2769// [public] activityTickle
2770//
2771// The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
2772// flag to be set, and the device state checked. If the device has been
2773// powered down, it is powered up again.
2d21ac55
A
2774// The tickle with parameter kIOPMSubclassPolicy is ignored here and
2775// should be intercepted by a subclass.
1c79356b
A
2776//*********************************************************************************
2777
39236c6e 2778bool IOService::activityTickle( unsigned long type, unsigned long stateNumber )
1c79356b 2779{
2d21ac55
A
2780 IOPMRequest * request;
2781 bool noPowerChange = true;
bd504ef0 2782 uint32_t tickleFlags;
e7c99d92 2783
db609669
A
2784 if (!initialized)
2785 return true; // no power change
2786
39236c6e 2787 if ((type == kIOPMSuperclassPolicy1) && StateOrder(stateNumber))
2d21ac55
A
2788 {
2789 IOLockLock(fActivityLock);
e7c99d92 2790
2d21ac55 2791 // Record device activity for the idle timer handler.
e7c99d92 2792
6d2010ae 2793 fDeviceWasActive = true;
b0d623f7 2794 fActivityTickleCount++;
2d21ac55 2795 clock_get_uptime(&fDeviceActiveTimestamp);
55e303ae 2796
6d2010ae 2797 PM_ACTION_0(actionActivityTickle);
b0d623f7 2798
2d21ac55
A
2799 // Record the last tickle power state.
2800 // This helps to filter out redundant tickles as
2801 // this function may be called from the data path.
1c79356b 2802
39236c6e
A
2803 if ((fActivityTicklePowerState == kInvalidTicklePowerState)
2804 || StateOrder(fActivityTicklePowerState) < StateOrder(stateNumber))
2d21ac55
A
2805 {
2806 fActivityTicklePowerState = stateNumber;
2807 noPowerChange = false;
1c79356b 2808
bd504ef0 2809 tickleFlags = kTickleTypeActivity | kTickleTypePowerRise;
2d21ac55
A
2810 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2811 if (request)
2812 {
39236c6e
A
2813 request->fArg0 = (void *) stateNumber;
2814 request->fArg1 = (void *)(uintptr_t) tickleFlags;
2815 request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
2d21ac55
A
2816 submitPMRequest(request);
2817 }
2818 }
1c79356b 2819
2d21ac55
A
2820 IOLockUnlock(fActivityLock);
2821 }
1c79356b 2822
db609669 2823 else if ((type == kIOPMActivityTickleTypeAdvisory) &&
39236c6e 2824 ((stateNumber = fDeviceUsablePowerState) != kPowerStateZero))
db609669
A
2825 {
2826 IOLockLock(fActivityLock);
2827
2828 fAdvisoryTickled = true;
2829
39236c6e 2830 if (fAdvisoryTicklePowerState != stateNumber)
db609669
A
2831 {
2832 fAdvisoryTicklePowerState = stateNumber;
2833 noPowerChange = false;
2834
bd504ef0 2835 tickleFlags = kTickleTypeAdvisory | kTickleTypePowerRise;
db609669
A
2836 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2837 if (request)
2838 {
39236c6e
A
2839 request->fArg0 = (void *) stateNumber;
2840 request->fArg1 = (void *)(uintptr_t) tickleFlags;
2841 request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
db609669
A
2842 submitPMRequest(request);
2843 }
2844 }
2845
2846 IOLockUnlock(fActivityLock);
2847 }
2848
2d21ac55
A
2849 // Returns false if the activityTickle might cause a transition to a
2850 // higher powered state, true otherwise.
2851
2852 return noPowerChange;
2853}
1c79356b
A
2854
2855//*********************************************************************************
b0d623f7
A
2856// [private] handleActivityTickle
2857//*********************************************************************************
2858
39236c6e 2859void IOService::handleActivityTickle( IOPMRequest * request )
b0d623f7 2860{
db609669 2861 uint32_t ticklePowerState = (uint32_t)(uintptr_t) request->fArg0;
bd504ef0
A
2862 uint32_t tickleFlags = (uint32_t)(uintptr_t) request->fArg1;
2863 uint32_t tickleGeneration = (uint32_t)(uintptr_t) request->fArg2;
db609669
A
2864 bool adjustPower = false;
2865
b0d623f7 2866 PM_ASSERT_IN_GATE();
bd504ef0
A
2867 if (fResetPowerStateOnWake && (tickleGeneration != gIOPMTickleGeneration))
2868 {
2869 // Drivers that don't want power restored on wake will drop any
2870 // tickles that pre-dates the current system wake. The model is
2871 // that each wake is a fresh start, with power state depressed
2872 // until a new tickle or an explicit power up request from the
2873 // driver. It is possible for the PM work loop to enter the
2874 // system sleep path with tickle requests queued.
2875
2876 return;
2877 }
2878
2879 if (tickleFlags & kTickleTypeActivity)
db609669 2880 {
39236c6e
A
2881 IOPMPowerStateIndex deviceDesireOrder = StateOrder(fDeviceDesire);
2882
bd504ef0 2883 if (tickleFlags & kTickleTypePowerRise)
db609669 2884 {
39236c6e 2885 if ((StateOrder(ticklePowerState) > deviceDesireOrder) &&
db609669
A
2886 (ticklePowerState < fNumberOfPowerStates))
2887 {
2888 fIdleTimerMinPowerState = ticklePowerState;
2889 updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
2890 adjustPower = true;
2891 }
2892 }
39236c6e 2893 else if (deviceDesireOrder > StateOrder(fIdleTimerMinPowerState))
db609669
A
2894 {
2895 // Power drop due to idle timer expiration.
2896 // Do not allow idle timer to reduce power below tickle power.
2897 // This prevents the idle timer from decreasing the device desire
2898 // to zero and cancelling the effect of a pre-sleep tickle when
2899 // system wakes up to doze state, while the device is unable to
2900 // raise its power state to satisfy the tickle.
39236c6e
A
2901
2902 deviceDesireOrder--;
2903 if (deviceDesireOrder < fNumberOfPowerStates)
2904 {
2905 ticklePowerState = fPowerStates[deviceDesireOrder].stateOrderToIndex;
2906 updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
2907 adjustPower = true;
2908 }
db609669
A
2909 }
2910 }
2911 else // advisory tickle
2912 {
bd504ef0 2913 if (tickleFlags & kTickleTypePowerRise)
db609669
A
2914 {
2915 if ((ticklePowerState == fDeviceUsablePowerState) &&
2916 (ticklePowerState < fNumberOfPowerStates))
2917 {
2918 updatePowerClient(gIOPMPowerClientAdvisoryTickle, ticklePowerState);
2919 fHasAdvisoryDesire = true;
2920 fAdvisoryTickleUsed = true;
2921 adjustPower = true;
2922 }
2923 else
2924 {
2925 IOLockLock(fActivityLock);
2926 fAdvisoryTicklePowerState = kInvalidTicklePowerState;
2927 IOLockUnlock(fActivityLock);
2928 }
2929 }
2930 else if (fHasAdvisoryDesire)
2931 {
2932 removePowerClient(gIOPMPowerClientAdvisoryTickle);
2933 fHasAdvisoryDesire = false;
2934 adjustPower = true;
2935 }
2936 }
b0d623f7
A
2937
2938 if (adjustPower)
2939 {
b0d623f7
A
2940 adjustPowerState();
2941 }
2942}
2943
6d2010ae 2944//******************************************************************************
b0d623f7 2945// [public] setIdleTimerPeriod
1c79356b 2946//
6d2010ae
A
2947// A subclass policy-maker is using our standard idleness detection service.
2948// Start the idle timer. Period is in seconds.
2949//******************************************************************************
1c79356b 2950
39236c6e 2951IOReturn IOService::setIdleTimerPeriod( unsigned long period )
1c79356b 2952{
b0d623f7 2953 if (!initialized)
2d21ac55
A
2954 return IOPMNotYetInitialized;
2955
6d2010ae 2956 OUR_PMLog(kPMLogSetIdleTimerPeriod, period, fIdleTimerPeriod);
1c79356b 2957
b0d623f7
A
2958 IOPMRequest * request =
2959 acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod );
2960 if (!request)
2961 return kIOReturnNoMemory;
1c79356b 2962
b0d623f7
A
2963 request->fArg0 = (void *) period;
2964 submitPMRequest( request );
2d21ac55 2965
6d2010ae 2966 return kIOReturnSuccess;
1c79356b
A
2967}
2968
7ddcb079
A
2969IOReturn IOService::setIgnoreIdleTimer( bool ignore )
2970{
2971 if (!initialized)
2972 return IOPMNotYetInitialized;
2973
2974 OUR_PMLog(kIOPMRequestTypeIgnoreIdleTimer, ignore, 0);
2975
2976 IOPMRequest * request =
2977 acquirePMRequest( this, kIOPMRequestTypeIgnoreIdleTimer );
2978 if (!request)
2979 return kIOReturnNoMemory;
2980
2981 request->fArg0 = (void *) ignore;
2982 submitPMRequest( request );
2983
2984 return kIOReturnSuccess;
2985}
2986
91447636 2987//******************************************************************************
b0d623f7 2988// [public] nextIdleTimeout
91447636
A
2989//
2990// Returns how many "seconds from now" the device should idle into its
2991// next lowest power state.
2992//******************************************************************************
2d21ac55 2993
91447636
A
2994SInt32 IOService::nextIdleTimeout(
2995 AbsoluteTime currentTime,
2996 AbsoluteTime lastActivity,
2997 unsigned int powerState)
2998{
6d2010ae
A
2999 AbsoluteTime delta;
3000 UInt64 delta_ns;
3001 SInt32 delta_secs;
3002 SInt32 delay_secs;
1c79356b 3003
91447636
A
3004 // Calculate time difference using funky macro from clock.h.
3005 delta = currentTime;
3006 SUB_ABSOLUTETIME(&delta, &lastActivity);
3007
3008 // Figure it in seconds.
3009 absolutetime_to_nanoseconds(delta, &delta_ns);
3010 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
3011
3012 // Be paranoid about delta somehow exceeding timer period.
b0d623f7 3013 if (delta_secs < (int) fIdleTimerPeriod)
2d21ac55 3014 delay_secs = (int) fIdleTimerPeriod - delta_secs;
91447636 3015 else
2d21ac55 3016 delay_secs = (int) fIdleTimerPeriod;
91447636
A
3017
3018 return (SInt32)delay_secs;
3019}
3020
6d2010ae 3021//*********************************************************************************
b0d623f7 3022// [public] start_PM_idle_timer
6d2010ae 3023//*********************************************************************************
2d21ac55 3024
39236c6e 3025void IOService::start_PM_idle_timer( void )
1c79356b 3026{
6d2010ae
A
3027 static const int maxTimeout = 100000;
3028 static const int minTimeout = 1;
3029 AbsoluteTime uptime, deadline;
3030 SInt32 idle_in = 0;
3031 boolean_t pending;
e7c99d92 3032
6d2010ae 3033 if (!initialized || !fIdleTimerPeriod)
2d21ac55
A
3034 return;
3035
3036 IOLockLock(fActivityLock);
e7c99d92
A
3037
3038 clock_get_uptime(&uptime);
6d2010ae 3039
91447636 3040 // Subclasses may modify idle sleep algorithm
2d21ac55 3041 idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, fCurrentPowerState);
e7c99d92 3042
91447636 3043 // Check for out-of range responses
2d21ac55 3044 if (idle_in > maxTimeout)
55e303ae 3045 {
91447636
A
3046 // use standard implementation
3047 idle_in = IOService::nextIdleTimeout(uptime,
2d21ac55
A
3048 fDeviceActiveTimestamp,
3049 fCurrentPowerState);
3050 } else if (idle_in < minTimeout) {
3051 idle_in = fIdleTimerPeriod;
e7c99d92
A
3052 }
3053
2d21ac55 3054 IOLockUnlock(fActivityLock);
e7c99d92 3055
6d2010ae
A
3056 retain();
3057 clock_interval_to_absolutetime_interval(idle_in, kSecondScale, &deadline);
3058 ADD_ABSOLUTETIME(&deadline, &uptime);
3059 pending = thread_call_enter_delayed(fIdleTimer, deadline);
3060 if (pending) release();
3061}
3062
bd504ef0
A
3063//*********************************************************************************
3064// [private] restartIdleTimer
3065//*********************************************************************************
3066
3067void IOService::restartIdleTimer( void )
3068{
39236c6e 3069 if (fDeviceDesire != kPowerStateZero)
bd504ef0
A
3070 {
3071 fIdleTimerStopped = false;
3072 fActivityTickleCount = 0;
3073 clock_get_uptime(&fIdleTimerStartTime);
3074 start_PM_idle_timer();
3075 }
3076 else if (fHasAdvisoryDesire)
3077 {
3078 fIdleTimerStopped = false;
3079 start_PM_idle_timer();
3080 }
3081 else
3082 {
3083 fIdleTimerStopped = true;
3084 }
3085}
3086
6d2010ae
A
3087//*********************************************************************************
3088// idle_timer_expired
3089//*********************************************************************************
3090
3091static void
39236c6e 3092idle_timer_expired(
6d2010ae
A
3093 thread_call_param_t arg0, thread_call_param_t arg1 )
3094{
3095 IOService * me = (IOService *) arg0;
3096
3097 if (gIOPMWorkLoop)
3098 gIOPMWorkLoop->runAction(
3099 OSMemberFunctionCast(IOWorkLoop::Action, me,
3100 &IOService::idleTimerExpired),
3101 me);
3102
3103 me->release();
1c79356b
A
3104}
3105
1c79356b 3106//*********************************************************************************
b0d623f7 3107// [private] idleTimerExpired
1c79356b 3108//
6d2010ae 3109// The idle timer has expired. If there has been activity since the last
1c79356b
A
3110// expiration, just restart the timer and return. If there has not been
3111// activity, switch to the next lower power state and restart the timer.
3112//*********************************************************************************
3113
6d2010ae 3114void IOService::idleTimerExpired( void )
1c79356b 3115{
2d21ac55
A
3116 IOPMRequest * request;
3117 bool restartTimer = true;
bd504ef0 3118 uint32_t tickleFlags;
2d21ac55 3119
bd504ef0
A
3120 if ( !initialized || !fIdleTimerPeriod || fIdleTimerStopped ||
3121 fLockedFlags.PMStop )
55e303ae 3122 return;
1c79356b 3123
2d21ac55 3124 IOLockLock(fActivityLock);
1c79356b 3125
2d21ac55 3126 // Check for device activity (tickles) over last timer period.
1c79356b 3127
6d2010ae 3128 if (fDeviceWasActive)
2d21ac55
A
3129 {
3130 // Device was active - do not drop power, restart timer.
6d2010ae 3131 fDeviceWasActive = false;
2d21ac55 3132 }
7ddcb079 3133 else if (!fIdleTimerIgnored)
2d21ac55
A
3134 {
3135 // No device activity - drop power state by one level.
3136 // Decrement the cached tickle power state when possible.
39236c6e
A
3137 // This value may be kInvalidTicklePowerState before activityTickle()
3138 // is called, but the power drop request must be issued regardless.
1c79356b 3139
39236c6e
A
3140 if ((fActivityTicklePowerState != kInvalidTicklePowerState) &&
3141 (fActivityTicklePowerState != kPowerStateZero))
2d21ac55 3142 fActivityTicklePowerState--;
1c79356b 3143
bd504ef0 3144 tickleFlags = kTickleTypeActivity | kTickleTypePowerDrop;
2d21ac55
A
3145 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3146 if (request)
3147 {
39236c6e
A
3148 request->fArg0 = (void *) kPowerStateZero; // irrelevant
3149 request->fArg1 = (void *)(uintptr_t) tickleFlags;
3150 request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
2d21ac55 3151 submitPMRequest( request );
1c79356b 3152
2d21ac55
A
3153 // Do not restart timer until after the tickle request has been
3154 // processed.
91447636 3155
2d21ac55
A
3156 restartTimer = false;
3157 }
1c79356b 3158 }
2d21ac55 3159
db609669
A
3160 if (fAdvisoryTickled)
3161 {
3162 fAdvisoryTickled = false;
3163 }
3164 else if (fHasAdvisoryDesire)
3165 {
3166 // Want new tickles to turn into pm request after we drop the lock
3167 fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3168
bd504ef0 3169 tickleFlags = kTickleTypeAdvisory | kTickleTypePowerDrop;
db609669
A
3170 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3171 if (request)
3172 {
39236c6e
A
3173 request->fArg0 = (void *) kPowerStateZero; // irrelevant
3174 request->fArg1 = (void *)(uintptr_t) tickleFlags;
3175 request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
db609669
A
3176 submitPMRequest( request );
3177
3178 // Do not restart timer until after the tickle request has been
3179 // processed.
3180
3181 restartTimer = false;
3182 }
3183 }
3184
2d21ac55
A
3185 IOLockUnlock(fActivityLock);
3186
3187 if (restartTimer)
3188 start_PM_idle_timer();
1c79356b
A
3189}
3190
b0d623f7 3191#ifndef __LP64__
2d21ac55 3192//*********************************************************************************
b0d623f7
A
3193// [deprecated] PM_idle_timer_expiration
3194//*********************************************************************************
3195
39236c6e 3196void IOService::PM_idle_timer_expiration( void )
b0d623f7
A
3197{
3198}
3199
3200//*********************************************************************************
3201// [deprecated] command_received
2d21ac55
A
3202//*********************************************************************************
3203
39236c6e 3204void IOService::command_received( void *statePtr , void *, void * , void * )
2d21ac55
A
3205{
3206}
b0d623f7 3207#endif /* !__LP64__ */
1c79356b
A
3208
3209//*********************************************************************************
b0d623f7 3210// [public] setAggressiveness
1c79356b
A
3211//
3212// Pass on the input parameters to all power domain children. All those which are
3213// power domains will pass it on to their children, etc.
3214//*********************************************************************************
3215
39236c6e 3216IOReturn IOService::setAggressiveness( unsigned long type, unsigned long newLevel )
1c79356b 3217{
b0d623f7 3218 return kIOReturnSuccess;
1c79356b
A
3219}
3220
3221//*********************************************************************************
b0d623f7 3222// [public] getAggressiveness
1c79356b
A
3223//
3224// Called by the user client.
3225//*********************************************************************************
3226
39236c6e 3227IOReturn IOService::getAggressiveness( unsigned long type, unsigned long * currentLevel )
1c79356b 3228{
b0d623f7 3229 IOPMrootDomain * rootDomain = getPMRootDomain();
55e303ae 3230
b0d623f7
A
3231 if (!rootDomain)
3232 return kIOReturnNotReady;
3233
3234 return rootDomain->getAggressiveness( type, currentLevel );
1c79356b
A
3235}
3236
3237//*********************************************************************************
2d21ac55
A
3238// [public] getPowerState
3239//
3240//*********************************************************************************
3241
39236c6e 3242UInt32 IOService::getPowerState( void )
2d21ac55
A
3243{
3244 if (!initialized)
39236c6e 3245 return kPowerStateZero;
2d21ac55
A
3246
3247 return fCurrentPowerState;
3248}
3249
b0d623f7 3250#ifndef __LP64__
2d21ac55 3251//*********************************************************************************
b0d623f7 3252// [deprecated] systemWake
1c79356b
A
3253//
3254// Pass this to all power domain children. All those which are
3255// power domains will pass it on to their children, etc.
3256//*********************************************************************************
3257
39236c6e 3258IOReturn IOService::systemWake( void )
1c79356b 3259{
2d21ac55
A
3260 OSIterator * iter;
3261 OSObject * next;
3262 IOPowerConnection * connection;
3263 IOService * theChild;
1c79356b 3264
1c79356b 3265 iter = getChildIterator(gIOPowerPlane);
2d21ac55 3266 if ( iter )
55e303ae 3267 {
2d21ac55 3268 while ( (next = iter->getNextObject()) )
55e303ae 3269 {
2d21ac55 3270 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
55e303ae 3271 {
2d21ac55
A
3272 if (connection->getReadyFlag() == false)
3273 {
6d2010ae 3274 PM_LOG3("[%s] %s: connection not ready\n",
2d21ac55
A
3275 getName(), __FUNCTION__);
3276 continue;
3277 }
3278
0b4e3aa0 3279 theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
2d21ac55 3280 if ( theChild )
55e303ae 3281 {
0b4e3aa0 3282 theChild->systemWake();
55e303ae 3283 theChild->release();
0b4e3aa0 3284 }
1c79356b
A
3285 }
3286 }
3287 iter->release();
3288 }
3289
2d21ac55 3290 if ( fControllingDriver != NULL )
55e303ae 3291 {
2d21ac55 3292 if ( fControllingDriver->didYouWakeSystem() )
55e303ae 3293 {
1c79356b
A
3294 makeUsable();
3295 }
3296 }
3297
3298 return IOPMNoErr;
3299}
3300
1c79356b 3301//*********************************************************************************
b0d623f7 3302// [deprecated] temperatureCriticalForZone
1c79356b
A
3303//*********************************************************************************
3304
39236c6e 3305IOReturn IOService::temperatureCriticalForZone( IOService * whichZone )
1c79356b 3306{
2d21ac55
A
3307 IOService * theParent;
3308 IOService * theNub;
0b4e3aa0 3309
2d21ac55 3310 OUR_PMLog(kPMLogCriticalTemp, 0, 0);
1c79356b 3311
6d2010ae 3312 if ( inPlane(gIOPowerPlane) && !IS_PM_ROOT )
55e303ae 3313 {
0b4e3aa0 3314 theNub = (IOService *)copyParentEntry(gIOPowerPlane);
2d21ac55 3315 if ( theNub )
55e303ae 3316 {
0b4e3aa0
A
3317 theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
3318 theNub->release();
2d21ac55 3319 if ( theParent )
55e303ae 3320 {
0b4e3aa0
A
3321 theParent->temperatureCriticalForZone(whichZone);
3322 theParent->release();
3323 }
3324 }
1c79356b
A
3325 }
3326 return IOPMNoErr;
3327}
b0d623f7 3328#endif /* !__LP64__ */
1c79356b 3329
6d2010ae
A
3330// MARK: -
3331// MARK: Power Change (Common)
1c79356b
A
3332
3333//*********************************************************************************
b0d623f7 3334// [private] startPowerChange
6d2010ae
A
3335//
3336// All power state changes starts here.
1c79356b
A
3337//*********************************************************************************
3338
6d2010ae
A
3339IOReturn IOService::startPowerChange(
3340 IOPMPowerChangeFlags changeFlags,
3341 IOPMPowerStateIndex powerState,
3342 IOPMPowerFlags domainFlags,
3343 IOPowerConnection * parentConnection,
3344 IOPMPowerFlags parentFlags )
2d21ac55 3345{
2d21ac55
A
3346 PM_ASSERT_IN_GATE();
3347 assert( fMachineState == kIOPM_Finished );
b0d623f7 3348 assert( powerState < fNumberOfPowerStates );
2d21ac55 3349
b0d623f7 3350 if (powerState >= fNumberOfPowerStates)
55e303ae 3351 return IOPMAckImplied;
1c79356b 3352
6d2010ae
A
3353 fIsPreChange = true;
3354 PM_ACTION_2(actionPowerChangeOverride, &powerState, &changeFlags);
b7266188 3355
39236c6e
A
3356 if (changeFlags & kIOPMExpireIdleTimer)
3357 {
3358 // Root domain requested removal of tickle influence
3359 if (StateOrder(fDeviceDesire) > StateOrder(powerState))
3360 {
3361 // Reset device desire down to the clamped power state
3362 updatePowerClient(gIOPMPowerClientDevice, powerState);
3363 computeDesiredState(kPowerStateZero, true);
3364
3365 // Invalidate tickle cache so the next tickle will issue a request
3366 IOLockLock(fActivityLock);
3367 fDeviceWasActive = false;
3368 fActivityTicklePowerState = kInvalidTicklePowerState;
3369 IOLockUnlock(fActivityLock);
3370
3371 fIdleTimerMinPowerState = kPowerStateZero;
3372 }
3373 }
3374
3375 // Root domain's override handler may cancel the power change by
3376 // setting the kIOPMNotDone flag.
3377
3378 if (changeFlags & kIOPMNotDone)
3379 return IOPMAckImplied;
3380
6d2010ae 3381 // Forks to either Driver or Parent initiated power change paths.
2d21ac55 3382
6d2010ae 3383 fHeadNoteChangeFlags = changeFlags;
b0d623f7
A
3384 fHeadNotePowerState = powerState;
3385 fHeadNotePowerArrayEntry = &fPowerStates[ powerState ];
3386 fHeadNoteParentConnection = NULL;
1c79356b 3387
6d2010ae 3388 if (changeFlags & kIOPMSelfInitiated)
2d21ac55 3389 {
b0d623f7
A
3390 if (changeFlags & kIOPMSynchronize)
3391 OurSyncStart();
3392 else
3393 OurChangeStart();
2d21ac55
A
3394 return 0;
3395 }
3396 else
3397 {
b0d623f7
A
3398 assert(changeFlags & kIOPMParentInitiated);
3399 fHeadNoteDomainFlags = domainFlags;
3400 fHeadNoteParentFlags = parentFlags;
3401 fHeadNoteParentConnection = parentConnection;
3402 return ParentChangeStart();
2d21ac55
A
3403 }
3404}
1c79356b 3405
2d21ac55
A
3406//*********************************************************************************
3407// [private] notifyInterestedDrivers
3408//*********************************************************************************
3409
39236c6e 3410bool IOService::notifyInterestedDrivers( void )
2d21ac55 3411{
6d2010ae
A
3412 IOPMinformee * informee;
3413 IOPMinformeeList * list = fInterestedDrivers;
3414 DriverCallParam * param;
3415 IOItemCount count;
2d21ac55 3416
6d2010ae
A
3417 PM_ASSERT_IN_GATE();
3418 assert( fDriverCallParamCount == 0 );
3419 assert( fHeadNotePendingAcks == 0 );
2d21ac55 3420
b0d623f7
A
3421 fHeadNotePendingAcks = 0;
3422
6d2010ae
A
3423 count = list->numberOfItems();
3424 if (!count)
3425 goto done; // no interested drivers
2d21ac55 3426
6d2010ae
A
3427 // Allocate an array of interested drivers and their return values
3428 // for the callout thread. Everything else is still "owned" by the
3429 // PM work loop, which can run to process acknowledgePowerChange()
3430 // responses.
2d21ac55 3431
6d2010ae
A
3432 param = (DriverCallParam *) fDriverCallParamPtr;
3433 if (count > fDriverCallParamSlots)
3434 {
3435 if (fDriverCallParamSlots)
3436 {
3437 assert(fDriverCallParamPtr);
3438 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
3439 fDriverCallParamPtr = 0;
3440 fDriverCallParamSlots = 0;
3441 }
2d21ac55 3442
6d2010ae
A
3443 param = IONew(DriverCallParam, count);
3444 if (!param)
3445 goto done; // no memory
2d21ac55 3446
6d2010ae
A
3447 fDriverCallParamPtr = (void *) param;
3448 fDriverCallParamSlots = count;
3449 }
2d21ac55 3450
6d2010ae
A
3451 informee = list->firstInList();
3452 assert(informee);
3453 for (IOItemCount i = 0; i < count; i++)
3454 {
3455 informee->timer = -1;
3456 param[i].Target = informee;
3457 informee->retain();
2d21ac55 3458 informee = list->nextInList( informee );
6d2010ae 3459 }
2d21ac55 3460
6d2010ae
A
3461 fDriverCallParamCount = count;
3462 fHeadNotePendingAcks = count;
2d21ac55 3463
6d2010ae
A
3464 // Block state machine and wait for callout completion.
3465 assert(!fDriverCallBusy);
3466 fDriverCallBusy = true;
3467 thread_call_enter( fDriverCallEntry );
3468 return true;
2d21ac55
A
3469
3470done:
6d2010ae
A
3471 // Return false if there are no interested drivers or could not schedule
3472 // callout thread due to error.
3473 return false;
2d21ac55
A
3474}
3475
3476//*********************************************************************************
3477// [private] notifyInterestedDriversDone
3478//*********************************************************************************
3479
39236c6e 3480void IOService::notifyInterestedDriversDone( void )
2d21ac55 3481{
6d2010ae
A
3482 IOPMinformee * informee;
3483 IOItemCount count;
3484 DriverCallParam * param;
3485 IOReturn result;
2d21ac55
A
3486
3487 PM_ASSERT_IN_GATE();
6d2010ae
A
3488 assert( fDriverCallBusy == false );
3489 assert( fMachineState == kIOPM_DriverThreadCallDone );
3490
2d21ac55
A
3491 param = (DriverCallParam *) fDriverCallParamPtr;
3492 count = fDriverCallParamCount;
3493
2d21ac55
A
3494 if (param && count)
3495 {
3496 for (IOItemCount i = 0; i < count; i++, param++)
3497 {
3498 informee = (IOPMinformee *) param->Target;
3499 result = param->Result;
3500
3501 if ((result == IOPMAckImplied) || (result < 0))
3502 {
b0d623f7
A
3503 // Interested driver return IOPMAckImplied.
3504 // If informee timer is zero, it must have de-registered
3505 // interest during the thread callout. That also drops
3506 // the pending ack count.
3507
3508 if (fHeadNotePendingAcks && informee->timer)
3509 fHeadNotePendingAcks--;
3510
3511 informee->timer = 0;
2d21ac55
A
3512 }
3513 else if (informee->timer)
3514 {
3515 assert(informee->timer == -1);
3516
3517 // Driver has not acked, and has returned a positive result.
3518 // Enforce a minimum permissible timeout value.
3519 // Make the min value large enough so timeout is less likely
3520 // to occur if a driver misinterpreted that the return value
3521 // should be in microsecond units. And make it large enough
3522 // to be noticeable if a driver neglects to ack.
3523
3524 if (result < kMinAckTimeoutTicks)
3525 result = kMinAckTimeoutTicks;
3526
3527 informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
3528 }
3529 // else, child has already acked or driver has removed interest,
3530 // and head_note_pendingAcks decremented.
3531 // informee may have been removed from the interested drivers list,
3532 // thus the informee must be retained across the callout.
3533
3534 informee->release();
3535 }
3536
3537 fDriverCallParamCount = 0;
3538
3539 if ( fHeadNotePendingAcks )
3540 {
3541 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
3542 start_ack_timer();
3543 }
3544 }
3545
39236c6e 3546 MS_POP(); // pop the machine state passed to notifyAll()
6d2010ae 3547
39236c6e
A
3548 // If interest acks are outstanding, block the state machine until
3549 // fHeadNotePendingAcks drops to zero before notifying root domain.
3550 // Otherwise notify root domain directly.
2d21ac55 3551
6d2010ae
A
3552 if (!fHeadNotePendingAcks)
3553 {
39236c6e 3554 notifyRootDomain();
6d2010ae
A
3555 }
3556 else
3557 {
3558 MS_PUSH(fMachineState);
3559 fMachineState = kIOPM_NotifyChildrenStart;
6d2010ae 3560 }
2d21ac55
A
3561}
3562
39236c6e
A
3563//*********************************************************************************
3564// [private] notifyRootDomain
3565//*********************************************************************************
3566
3567void IOService::notifyRootDomain( void )
3568{
3569 assert( fDriverCallBusy == false );
3570
3571 // Only for root domain in the will-change phase
3572 if (!IS_ROOT_DOMAIN || (fMachineState != kIOPM_OurChangeSetPowerState))
3573 {
3574 notifyChildren();
3575 return;
3576 }
3577
3578 MS_PUSH(fMachineState); // push notifyAll() machine state
3579 fMachineState = kIOPM_DriverThreadCallDone;
3580
3581 fDriverCallReason = kRootDomainInformPreChange;
3582 fDriverCallBusy = true;
3583 thread_call_enter( fDriverCallEntry );
3584}
3585
3586void IOService::notifyRootDomainDone( void )
3587{
3588 assert( fDriverCallBusy == false );
3589 assert( fMachineState == kIOPM_DriverThreadCallDone );
3590
3591 MS_POP(); // pop notifyAll() machine state
3592 notifyChildren();
3593}
3594
2d21ac55
A
3595//*********************************************************************************
3596// [private] notifyChildren
3597//*********************************************************************************
3598
39236c6e 3599void IOService::notifyChildren( void )
2d21ac55
A
3600{
3601 OSIterator * iter;
3602 OSObject * next;
3603 IOPowerConnection * connection;
3604 OSArray * children = 0;
6d2010ae
A
3605 IOPMrootDomain * rootDomain;
3606 bool delayNotify = false;
3607
3608 if ((fHeadNotePowerState != fCurrentPowerState) &&
3609 (IS_POWER_DROP == fIsPreChange) &&
3610 ((rootDomain = getPMRootDomain()) == this))
3611 {
3612 rootDomain->tracePoint( IS_POWER_DROP ?
3613 kIOPMTracePointSleepPowerPlaneDrivers :
3614 kIOPMTracePointWakePowerPlaneDrivers );
3615 }
1c79356b 3616
2d21ac55
A
3617 if (fStrictTreeOrder)
3618 children = OSArray::withCapacity(8);
1c79356b 3619
2d21ac55 3620 // Sum child power consumption in notifyChild()
b0d623f7 3621 fHeadNotePowerArrayEntry->staticPower = 0;
2d21ac55
A
3622
3623 iter = getChildIterator(gIOPowerPlane);
3624 if ( iter )
3625 {
3626 while ((next = iter->getNextObject()))
55e303ae 3627 {
2d21ac55
A
3628 if ((connection = OSDynamicCast(IOPowerConnection, next)))
3629 {
3630 if (connection->getReadyFlag() == false)
3631 {
6d2010ae 3632 PM_LOG3("[%s] %s: connection not ready\n",
2d21ac55
A
3633 getName(), __FUNCTION__);
3634 continue;
3635 }
3636
6d2010ae
A
3637 // Mechanism to postpone the did-change notification to
3638 // certain power children to order those children last.
3639 // Cannot be used together with strict tree ordering.
3640
3641 if (!fIsPreChange &&
3642 (connection->delayChildNotification) &&
3643 getPMRootDomain()->shouldDelayChildNotification(this))
3644 {
3645 if (!children)
3646 {
3647 children = OSArray::withCapacity(8);
3648 if (children)
3649 delayNotify = true;
3650 }
3651 if (delayNotify)
3652 {
3653 children->setObject( connection );
3654 continue;
3655 }
3656 }
3657
3658 if (!delayNotify && children)
2d21ac55
A
3659 children->setObject( connection );
3660 else
6d2010ae 3661 notifyChild( connection );
2d21ac55 3662 }
1c79356b 3663 }
2d21ac55 3664 iter->release();
1c79356b
A
3665 }
3666
6d2010ae
A
3667 if (children && (children->getCount() == 0))
3668 {
3669 children->release();
3670 children = 0;
3671 }
2d21ac55
A
3672 if (children)
3673 {
6d2010ae
A
3674 assert(fNotifyChildArray == 0);
3675 fNotifyChildArray = children;
3676 MS_PUSH(fMachineState);
3677
3678 if (delayNotify)
3679 {
3680 // Wait for exiting child notifications to complete,
3681 // before notifying the children in the array.
3682 fMachineState = kIOPM_NotifyChildrenDelayed;
3683 PM_LOG2("%s: %d children in delayed array\n",
3684 getName(), children->getCount());
3685 }
3686 else
3687 {
3688 // Notify children in the array one at a time.
3689 fMachineState = kIOPM_NotifyChildrenOrdered;
3690 }
2d21ac55
A
3691 }
3692}
1c79356b 3693
2d21ac55 3694//*********************************************************************************
6d2010ae 3695// [private] notifyChildrenOrdered
2d21ac55 3696//*********************************************************************************
1c79356b 3697
39236c6e 3698void IOService::notifyChildrenOrdered( void )
2d21ac55
A
3699{
3700 PM_ASSERT_IN_GATE();
3701 assert(fNotifyChildArray);
6d2010ae 3702 assert(fMachineState == kIOPM_NotifyChildrenOrdered);
2d21ac55 3703
b0d623f7 3704 // Notify one child, wait for it to ack, then repeat for next child.
2d21ac55
A
3705 // This is a workaround for some drivers with multiple instances at
3706 // the same branch in the power tree, but the driver is slow to power
3707 // up unless the tree ordering is observed. Problem observed only on
3708 // system wake, not on system sleep.
3709 //
3710 // We have the ability to power off in reverse child index order.
3711 // That works nicely on some machines, but not on all HW configs.
3712
3713 if (fNotifyChildArray->getCount())
3714 {
3715 IOPowerConnection * connection;
3716 connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
6d2010ae 3717 notifyChild( connection );
440d4c6c 3718 fNotifyChildArray->removeObject(0);
2d21ac55
A
3719 }
3720 else
3721 {
3722 fNotifyChildArray->release();
3723 fNotifyChildArray = 0;
6d2010ae
A
3724
3725 MS_POP(); // pushed by notifyChildren()
2d21ac55 3726 }
1c79356b
A
3727}
3728
6d2010ae
A
3729//*********************************************************************************
3730// [private] notifyChildrenDelayed
3731//*********************************************************************************
3732
39236c6e 3733void IOService::notifyChildrenDelayed( void )
6d2010ae
A
3734{
3735 IOPowerConnection * connection;
3736
3737 PM_ASSERT_IN_GATE();
3738 assert(fNotifyChildArray);
3739 assert(fMachineState == kIOPM_NotifyChildrenDelayed);
3740
3741 // Wait after all non-delayed children and interested drivers have ack'ed,
3742 // then notify all delayed children. When explicitly cancelled, interest
3743 // acks (and ack timer) may still be outstanding.
3744
3745 for (int i = 0; ; i++)
3746 {
3747 connection = (IOPowerConnection *) fNotifyChildArray->getObject(i);
3748 if (!connection)
3749 break;
3750
3751 notifyChild( connection );
3752 }
3753
3754 PM_LOG2("%s: notified delayed children\n", getName());
3755 fNotifyChildArray->release();
3756 fNotifyChildArray = 0;
3757
3758 MS_POP(); // pushed by notifyChildren()
3759}
3760
1c79356b 3761//*********************************************************************************
2d21ac55 3762// [private] notifyAll
1c79356b
A
3763//*********************************************************************************
3764
39236c6e 3765IOReturn IOService::notifyAll( uint32_t nextMS )
1c79356b 3766{
39236c6e 3767 // Save the machine state to be restored by notifyInterestedDriversDone()
1c79356b 3768
2d21ac55 3769 PM_ASSERT_IN_GATE();
6d2010ae 3770 MS_PUSH(nextMS);
2d21ac55 3771 fMachineState = kIOPM_DriverThreadCallDone;
6d2010ae 3772 fDriverCallReason = fIsPreChange ?
2d21ac55 3773 kDriverCallInformPreChange : kDriverCallInformPostChange;
6601e61a 3774
2d21ac55
A
3775 if (!notifyInterestedDrivers())
3776 notifyInterestedDriversDone();
55e303ae 3777
2d21ac55
A
3778 return IOPMWillAckLater;
3779}
0c530ab8 3780
2d21ac55
A
3781//*********************************************************************************
3782// [private, static] pmDriverCallout
3783//
3784// Thread call context
3785//*********************************************************************************
0c530ab8 3786
39236c6e 3787IOReturn IOService::actionDriverCalloutDone(
2d21ac55
A
3788 OSObject * target,
3789 void * arg0, void * arg1,
3790 void * arg2, void * arg3 )
3791{
6d2010ae 3792 IOServicePM * pwrMgt = (IOServicePM *) arg0;
0c530ab8 3793
6d2010ae
A
3794 assert( fDriverCallBusy );
3795 fDriverCallBusy = false;
1c79356b 3796
6d2010ae
A
3797 assert(gIOPMWorkQueue);
3798 gIOPMWorkQueue->signalWorkAvailable();
1c79356b 3799
6d2010ae 3800 return kIOReturnSuccess;
2d21ac55 3801}
1c79356b 3802
39236c6e 3803void IOService::pmDriverCallout( IOService * from )
2d21ac55
A
3804{
3805 assert(from);
3806 switch (from->fDriverCallReason)
3807 {
3808 case kDriverCallSetPowerState:
3809 from->driverSetPowerState();
3810 break;
3811
3812 case kDriverCallInformPreChange:
3813 case kDriverCallInformPostChange:
3814 from->driverInformPowerChange();
3815 break;
3816
39236c6e
A
3817 case kRootDomainInformPreChange:
3818 getPMRootDomain()->willNotifyPowerChildren(from->fHeadNotePowerState);
3819 break;
3820
2d21ac55 3821 default:
b0d623f7
A
3822 panic("IOService::pmDriverCallout bad machine state %x",
3823 from->fDriverCallReason);
2d21ac55
A
3824 }
3825
3826 gIOPMWorkLoop->runAction(actionDriverCalloutDone,
3827 /* target */ from,
3828 /* arg0 */ (void *) from->pwrMgt );
3829}
3830
3831//*********************************************************************************
3832// [private] driverSetPowerState
3833//
3834// Thread call context
3835//*********************************************************************************
3836
39236c6e 3837void IOService::driverSetPowerState( void )
2d21ac55 3838{
6d2010ae
A
3839 IOPMPowerStateIndex powerState;
3840 DriverCallParam * param;
3841 IOPMDriverCallEntry callEntry;
2d21ac55 3842 AbsoluteTime end;
6d2010ae
A
3843 IOReturn result;
3844 uint32_t oldPowerState = getPowerState();
2d21ac55 3845
6d2010ae
A
3846 assert( fDriverCallBusy );
3847 assert( fDriverCallParamPtr );
3848 assert( fDriverCallParamCount == 1 );
2d21ac55 3849
6d2010ae
A
3850 param = (DriverCallParam *) fDriverCallParamPtr;
3851 powerState = fHeadNotePowerState;
2d21ac55 3852
6d2010ae
A
3853 if (assertPMDriverCall(&callEntry))
3854 {
3855 OUR_PMLog( kPMLogProgramHardware, (uintptr_t) this, powerState);
2d21ac55 3856 clock_get_uptime(&fDriverCallStartTime);
6d2010ae 3857 result = fControllingDriver->setPowerState( powerState, this );
2d21ac55 3858 clock_get_uptime(&end);
6d2010ae
A
3859 OUR_PMLog((UInt32) -kPMLogProgramHardware, (uintptr_t) this, (UInt32) result);
3860
3861 deassertPMDriverCall(&callEntry);
3862
3863 if (result < 0)
3864 {
3865 PM_LOG("%s::setPowerState(%p, %lu -> %lu) returned 0x%x\n",
3866 fName, this, fCurrentPowerState, powerState, result);
3867 }
2d21ac55
A
3868
3869#if LOG_SETPOWER_TIMES
3870 if ((result == IOPMAckImplied) || (result < 0))
55e303ae 3871 {
2d21ac55 3872 uint64_t nsec;
0c530ab8 3873
2d21ac55
A
3874 SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
3875 absolutetime_to_nanoseconds(end, &nsec);
3876 if (nsec > LOG_SETPOWER_TIMES)
6d2010ae 3877 PM_LOG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
2d21ac55 3878 fName, this, fCurrentPowerState, powerState, NS_TO_MS(nsec));
6d2010ae
A
3879
3880 PMEventDetails *details = PMEventDetails::eventDetails(
3881 kIOPMEventTypeSetPowerStateImmediate, // type
3882 fName, // who
3883 (uintptr_t)this, // owner unique
3884 NULL, // interest name
3885 (uint8_t)oldPowerState, // old
3886 (uint8_t)powerState, // new
3887 0, // result
3888 NS_TO_US(nsec)); // usec completion time
3889
39236c6e 3890 getPMRootDomain()->recordAndReleasePMEvent( details );
1c79356b 3891 }
2d21ac55 3892#endif
6d2010ae
A
3893 }
3894 else
3895 result = kIOPMAckImplied;
1c79356b 3896
6d2010ae 3897 param->Result = result;
2d21ac55 3898}
55e303ae 3899
2d21ac55
A
3900//*********************************************************************************
3901// [private] driverInformPowerChange
3902//
3903// Thread call context
3904//*********************************************************************************
0c530ab8 3905
39236c6e 3906void IOService::driverInformPowerChange( void )
2d21ac55 3907{
6d2010ae
A
3908 IOPMinformee * informee;
3909 IOService * driver;
3910 DriverCallParam * param;
3911 IOPMDriverCallEntry callEntry;
3912 IOPMPowerFlags powerFlags;
3913 IOPMPowerStateIndex powerState;
2d21ac55 3914 AbsoluteTime end;
6d2010ae
A
3915 IOReturn result;
3916 IOItemCount count;
2d21ac55 3917
6d2010ae
A
3918 assert( fDriverCallBusy );
3919 assert( fDriverCallParamPtr );
3920 assert( fDriverCallParamCount );
2d21ac55 3921
6d2010ae
A
3922 param = (DriverCallParam *) fDriverCallParamPtr;
3923 count = fDriverCallParamCount;
2d21ac55 3924
6d2010ae
A
3925 powerFlags = fHeadNotePowerArrayEntry->capabilityFlags;
3926 powerState = fHeadNotePowerState;
2d21ac55 3927
6d2010ae
A
3928 for (IOItemCount i = 0; i < count; i++)
3929 {
3930 informee = (IOPMinformee *) param->Target;
3931 driver = informee->whatObject;
3932
3933 if (assertPMDriverCall(&callEntry, 0, informee))
3934 {
3935 if (fDriverCallReason == kDriverCallInformPreChange)
3936 {
3937 OUR_PMLog(kPMLogInformDriverPreChange, (uintptr_t) this, powerState);
2d21ac55 3938 clock_get_uptime(&informee->startTime);
6d2010ae 3939 result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
2d21ac55 3940 clock_get_uptime(&end);
6d2010ae
A
3941 OUR_PMLog((UInt32)-kPMLogInformDriverPreChange, (uintptr_t) this, result);
3942 }
3943 else
3944 {
3945 OUR_PMLog(kPMLogInformDriverPostChange, (uintptr_t) this, powerState);
3946 clock_get_uptime(&informee->startTime);
3947 result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
3948 clock_get_uptime(&end);
3949 OUR_PMLog((UInt32)-kPMLogInformDriverPostChange, (uintptr_t) this, result);
3950 }
3951
3952 deassertPMDriverCall(&callEntry);
2d21ac55
A
3953
3954#if LOG_SETPOWER_TIMES
3955 if ((result == IOPMAckImplied) || (result < 0))
3956 {
3957 uint64_t nsec;
3958
3959 SUB_ABSOLUTETIME(&end, &informee->startTime);
3960 absolutetime_to_nanoseconds(end, &nsec);
3961 if (nsec > LOG_SETPOWER_TIMES)
6d2010ae 3962 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
2d21ac55
A
3963 driver->getName(),
3964 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
3965 driver, fName, fCurrentPowerState, powerState, NS_TO_MS(nsec));
6d2010ae
A
3966
3967 uint16_t logType = (fDriverCallReason == kDriverCallInformPreChange)
3968 ? kIOPMEventTypePSWillChangeTo
3969 : kIOPMEventTypePSDidChangeTo;
3970
3971 PMEventDetails *details = PMEventDetails::eventDetails(
3972 logType, // type
3973 fName, // who
3974 (uintptr_t)this, // owner unique
3975 driver->getName(), // interest name
3976 (uint8_t)fCurrentPowerState, // old
3977 (uint8_t)fHeadNotePowerState, // new
3978 0, // result
3979 NS_TO_US(nsec)); // usec completion time
3980
39236c6e 3981 getPMRootDomain()->recordAndReleasePMEvent( details );
2d21ac55
A
3982 }
3983#endif
6d2010ae
A
3984 }
3985 else
3986 result = kIOPMAckImplied;
0c530ab8 3987
6d2010ae
A
3988 param->Result = result;
3989 param++;
3990 }
1c79356b
A
3991}
3992
1c79356b 3993//*********************************************************************************
2d21ac55 3994// [private] notifyChild
1c79356b
A
3995//
3996// Notify a power domain child of an upcoming power change.
1c79356b
A
3997// If the object acknowledges the current change, we return TRUE.
3998//*********************************************************************************
3999
39236c6e 4000bool IOService::notifyChild( IOPowerConnection * theNub )
1c79356b 4001{
6d2010ae
A
4002 IOReturn ret = IOPMAckImplied;
4003 unsigned long childPower;
4004 IOService * theChild;
4005 IOPMRequest * childRequest;
4006 IOPMPowerChangeFlags requestArg2;
4007 int requestType;
2d21ac55
A
4008
4009 PM_ASSERT_IN_GATE();
3a60a9f5 4010 theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
2d21ac55 4011 if (!theChild)
55e303ae 4012 {
0b4e3aa0 4013 return true;
55e303ae 4014 }
2d21ac55 4015
3a60a9f5
A
4016 // Unless the child handles the notification immediately and returns
4017 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
2d21ac55 4018 fHeadNotePendingAcks++;
3a60a9f5 4019 theNub->setAwaitingAck(true);
b0d623f7 4020
6d2010ae 4021 requestArg2 = fHeadNoteChangeFlags;
39236c6e 4022 if (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState))
b0d623f7
A
4023 requestArg2 |= kIOPMDomainPowerDrop;
4024
6d2010ae 4025 requestType = fIsPreChange ?
b0d623f7
A
4026 kIOPMRequestTypePowerDomainWillChange :
4027 kIOPMRequestTypePowerDomainDidChange;
2d21ac55
A
4028
4029 childRequest = acquirePMRequest( theChild, requestType );
4030 if (childRequest)
4031 {
cf7d32b8 4032 theNub->retain();
39236c6e
A
4033 childRequest->fArg0 = (void *) fHeadNotePowerArrayEntry->outputPowerFlags;
4034 childRequest->fArg1 = (void *) theNub;
4035 childRequest->fArg2 = (void *)(uintptr_t) requestArg2;
2d21ac55 4036 theChild->submitPMRequest( childRequest );
b0d623f7 4037 ret = IOPMWillAckLater;
2d21ac55
A
4038 }
4039 else
4040 {
b0d623f7 4041 ret = IOPMAckImplied;
2d21ac55
A
4042 fHeadNotePendingAcks--;
4043 theNub->setAwaitingAck(false);
0b4e3aa0 4044 childPower = theChild->currentPowerConsumption();
2d21ac55 4045 if ( childPower == kIOPMUnknown )
55e303ae 4046 {
b0d623f7 4047 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
55e303ae 4048 } else {
b0d623f7
A
4049 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown )
4050 fHeadNotePowerArrayEntry->staticPower += childPower;
0b4e3aa0 4051 }
55e303ae 4052 }
55e303ae 4053
2d21ac55 4054 theChild->release();
b0d623f7 4055 return (IOPMAckImplied == ret);
1c79356b
A
4056}
4057
6d2010ae
A
4058//*********************************************************************************
4059// [private] notifyControllingDriver
4060//*********************************************************************************
4061
39236c6e 4062bool IOService::notifyControllingDriver( void )
6d2010ae
A
4063{
4064 DriverCallParam * param;
4065
4066 PM_ASSERT_IN_GATE();
4067 assert( fDriverCallParamCount == 0 );
4068 assert( fControllingDriver );
4069
4070 if (fInitialSetPowerState)
4071 {
316670eb
A
4072 fInitialSetPowerState = false;
4073 fHeadNoteChangeFlags |= kIOPMInitialPowerChange;
4074
6d2010ae
A
4075 // Driver specified flag to skip the inital setPowerState()
4076 if (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState)
4077 {
4078 return false;
4079 }
6d2010ae
A
4080 }
4081
4082 param = (DriverCallParam *) fDriverCallParamPtr;
4083 if (!param)
4084 {
4085 param = IONew(DriverCallParam, 1);
4086 if (!param)
4087 return false; // no memory
4088
4089 fDriverCallParamPtr = (void *) param;
4090 fDriverCallParamSlots = 1;
4091 }
4092
4093 param->Target = fControllingDriver;
4094 fDriverCallParamCount = 1;
4095 fDriverTimer = -1;
4096
4097 // Block state machine and wait for callout completion.
4098 assert(!fDriverCallBusy);
4099 fDriverCallBusy = true;
4100 thread_call_enter( fDriverCallEntry );
4101
4102 return true;
4103}
4104
4105//*********************************************************************************
4106// [private] notifyControllingDriverDone
4107//*********************************************************************************
4108
4109void IOService::notifyControllingDriverDone( void )
4110{
4111 DriverCallParam * param;
4112 IOReturn result;
4113
4114 PM_ASSERT_IN_GATE();
4115 param = (DriverCallParam *) fDriverCallParamPtr;
4116
4117 assert( fDriverCallBusy == false );
4118 assert( fMachineState == kIOPM_DriverThreadCallDone );
4119
4120 if (param && fDriverCallParamCount)
4121 {
4122 assert(fDriverCallParamCount == 1);
4123
4124 // the return value from setPowerState()
4125 result = param->Result;
4126
4127 if ((result == IOPMAckImplied) || (result < 0))
4128 {
4129 fDriverTimer = 0;
4130 }
4131 else if (fDriverTimer)
4132 {
4133 assert(fDriverTimer == -1);
4134
4135 // Driver has not acked, and has returned a positive result.
4136 // Enforce a minimum permissible timeout value.
4137 // Make the min value large enough so timeout is less likely
4138 // to occur if a driver misinterpreted that the return value
4139 // should be in microsecond units. And make it large enough
4140 // to be noticeable if a driver neglects to ack.
4141
4142 if (result < kMinAckTimeoutTicks)
4143 result = kMinAckTimeoutTicks;
4144
4145 fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
4146 }
4147 // else, child has already acked and driver_timer reset to 0.
4148
4149 fDriverCallParamCount = 0;
4150
4151 if ( fDriverTimer )
4152 {
4153 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
4154 start_ack_timer();
4155 }
4156 }
4157
4158 MS_POP(); // pushed by OurChangeSetPowerState()
4159 fIsPreChange = false;
4160}
4161
4162//*********************************************************************************
4163// [private] all_done
4164//
4165// A power change is done.
4166//*********************************************************************************
4167
39236c6e 4168void IOService::all_done( void )
6d2010ae
A
4169{
4170 IOPMPowerStateIndex prevPowerState;
4171 const IOPMPSEntry * powerStatePtr;
4172 IOPMDriverCallEntry callEntry;
4173 uint32_t prevMachineState = fMachineState;
4174 bool callAction = false;
39236c6e 4175 uint64_t ts;
6d2010ae
A
4176
4177 fMachineState = kIOPM_Finished;
4178
4179 if ((fHeadNoteChangeFlags & kIOPMSynchronize) &&
4180 ((prevMachineState == kIOPM_Finished) ||
4181 (prevMachineState == kIOPM_SyncFinish)))
4182 {
4183 // Sync operation and no power change occurred.
4184 // Do not inform driver and clients about this request completion,
4185 // except for the originator (root domain).
4186
4187 PM_ACTION_2(actionPowerChangeDone,
4188 fHeadNotePowerState, fHeadNoteChangeFlags);
4189
4190 if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree)
4191 {
4192 powerChangeDone(fCurrentPowerState);
4193 }
db609669
A
4194 else if (fAdvisoryTickleUsed)
4195 {
bd504ef0 4196 // Not root domain and advisory tickle target.
db609669 4197 // Re-adjust power after power tree sync at the 'did' pass
bd504ef0
A
4198 // to recompute desire and adjust power state between dark
4199 // and full wake transitions. Root domain is responsible
4200 // for calling setAdvisoryTickleEnable() before starting
4201 // the kIOPMSynchronize power change.
4202
db609669
A
4203 if (!fAdjustPowerScheduled &&
4204 (fHeadNoteChangeFlags & kIOPMDomainDidChange))
4205 {
4206 IOPMRequest * request;
4207 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
4208 if (request)
4209 {
4210 submitPMRequest( request );
4211 fAdjustPowerScheduled = true;
4212 }
4213 }
4214 }
6d2010ae
A
4215
4216 return;
4217 }
4218
4219 // our power change
4220 if ( fHeadNoteChangeFlags & kIOPMSelfInitiated )
4221 {
4222 // could our driver switch to the new state?
4223 if ( !( fHeadNoteChangeFlags & kIOPMNotDone) )
4224 {
316670eb
A
4225 trackSystemSleepPreventers(
4226 fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4227
6d2010ae
A
4228 // we changed, tell our parent
4229 requestDomainPower(fHeadNotePowerState);
4230
4231 // yes, did power raise?
39236c6e 4232 if ( StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState) )
6d2010ae
A
4233 {
4234 // yes, inform clients and apps
4235 tellChangeUp (fHeadNotePowerState);
4236 }
4237 prevPowerState = fCurrentPowerState;
4238 // either way
4239 fCurrentPowerState = fHeadNotePowerState;
39236c6e
A
4240 PM_LOCK();
4241 if (fReportBuf) {
4242 ts = mach_absolute_time();
4243 STATEREPORT_SETSTATE(fReportBuf, fCurrentPowerState, ts);
4244 }
4245 PM_UNLOCK();
6d2010ae
A
4246#if PM_VARS_SUPPORT
4247 fPMVars->myCurrentState = fCurrentPowerState;
4248#endif
4b17d6b6 4249 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
6d2010ae
A
4250 PM_ACTION_2(actionPowerChangeDone,
4251 fHeadNotePowerState, fHeadNoteChangeFlags);
4252 callAction = true;
4253
4254 powerStatePtr = &fPowerStates[fCurrentPowerState];
4255 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4256 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
4257 fCurrentPowerConsumption = powerStatePtr->staticPower;
4258
bd504ef0
A
4259 if (fHeadNoteChangeFlags & kIOPMRootChangeDown)
4260 {
4261 // Bump tickle generation count once the entire tree is down
4262 gIOPMTickleGeneration++;
4263 }
4264
6d2010ae
A
4265 // inform subclass policy-maker
4266 if (fPCDFunctionOverride && fParentsKnowState &&
4267 assertPMDriverCall(&callEntry, kIOPMADC_NoInactiveCheck))
4268 {
4269 powerChangeDone(prevPowerState);
4270 deassertPMDriverCall(&callEntry);
4271 }
4272 }
4273 else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)
4274 {
4275 // changePowerStateWithOverrideTo() was cancelled
4276 fOverrideMaxPowerState = kIOPMPowerStateMax;
4277 }
4278 }
4279
4280 // parent's power change
4281 if ( fHeadNoteChangeFlags & kIOPMParentInitiated)
4282 {
bd504ef0
A
4283 if (fHeadNoteChangeFlags & kIOPMRootChangeDown)
4284 ParentChangeRootChangeDown();
4285
6d2010ae 4286 if (((fHeadNoteChangeFlags & kIOPMDomainWillChange) &&
39236c6e 4287 (StateOrder(fCurrentPowerState) >= StateOrder(fHeadNotePowerState))) ||
6d2010ae 4288 ((fHeadNoteChangeFlags & kIOPMDomainDidChange) &&
39236c6e 4289 (StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState))))
6d2010ae 4290 {
316670eb
A
4291 trackSystemSleepPreventers(
4292 fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
7ee9d059 4293
6d2010ae 4294 // did power raise?
39236c6e 4295 if ( StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState) )
6d2010ae
A
4296 {
4297 // yes, inform clients and apps
4298 tellChangeUp (fHeadNotePowerState);
4299 }
4300 // either way
4301 prevPowerState = fCurrentPowerState;
4302 fCurrentPowerState = fHeadNotePowerState;
39236c6e
A
4303 PM_LOCK();
4304 if (fReportBuf) {
4305 ts = mach_absolute_time();
4306 STATEREPORT_SETSTATE(fReportBuf, fCurrentPowerState, ts);
4307 }
4308 PM_UNLOCK();
6d2010ae
A
4309#if PM_VARS_SUPPORT
4310 fPMVars->myCurrentState = fCurrentPowerState;
4311#endif
4312 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fHeadNoteDomainFlags);
4313
4b17d6b6 4314 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
6d2010ae
A
4315 PM_ACTION_2(actionPowerChangeDone,
4316 fHeadNotePowerState, fHeadNoteChangeFlags);
4317 callAction = true;
4318
4319 powerStatePtr = &fPowerStates[fCurrentPowerState];
4320 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4321 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
4322 fCurrentPowerConsumption = powerStatePtr->staticPower;
4323
4324 // inform subclass policy-maker
4325 if (fPCDFunctionOverride && fParentsKnowState &&
4326 assertPMDriverCall(&callEntry, kIOPMADC_NoInactiveCheck))
4327 {
4328 powerChangeDone(prevPowerState);
4329 deassertPMDriverCall(&callEntry);
4330 }
4331 }
4332 }
4333
4334 // When power rises enough to satisfy the tickle's desire for more power,
4335 // the condition preventing idle-timer from dropping power is removed.
4336
39236c6e 4337 if (StateOrder(fCurrentPowerState) >= StateOrder(fIdleTimerMinPowerState))
6d2010ae 4338 {
39236c6e 4339 fIdleTimerMinPowerState = kPowerStateZero;
6d2010ae
A
4340 }
4341
4342 if (!callAction)
4343 {
4344 PM_ACTION_2(actionPowerChangeDone,
4345 fHeadNotePowerState, fHeadNoteChangeFlags);
4346 }
4347}
4348
7e4a7d39
A
4349// MARK: -
4350// MARK: Power Change Initiated by Driver
4351
4352//*********************************************************************************
4353// [private] OurChangeStart
4354//
4355// Begin the processing of a power change initiated by us.
4356//*********************************************************************************
4357
39236c6e 4358void IOService::OurChangeStart( void )
7e4a7d39
A
4359{
4360 PM_ASSERT_IN_GATE();
4361 OUR_PMLog( kPMLogStartDeviceChange, fHeadNotePowerState, fCurrentPowerState );
4362
6d2010ae 4363 // fMaxPowerState is our maximum possible power state based on the current
7e4a7d39
A
4364 // power state of our parents. If we are trying to raise power beyond the
4365 // maximum, send an async request for more power to all parents.
4366
39236c6e 4367 if (!IS_PM_ROOT && (StateOrder(fMaxPowerState) < StateOrder(fHeadNotePowerState)))
7e4a7d39 4368 {
6d2010ae 4369 fHeadNoteChangeFlags |= kIOPMNotDone;
7e4a7d39
A
4370 requestDomainPower(fHeadNotePowerState);
4371 OurChangeFinish();
4372 return;
4373 }
4374
4375 // Redundant power changes skips to the end of the state machine.
4376
6d2010ae 4377 if (!fInitialPowerChange && (fHeadNotePowerState == fCurrentPowerState))
7e4a7d39
A
4378 {
4379 OurChangeFinish();
4380 return;
4381 }
6d2010ae 4382 fInitialPowerChange = false;
7e4a7d39 4383
7e4a7d39
A
4384 // Change started, but may not complete...
4385 // Can be canceled (power drop) or deferred (power rise).
4386
6d2010ae 4387 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
7e4a7d39
A
4388
4389 // Two separate paths, depending if power is being raised or lowered.
4390 // Lowering power is subject to approval by clients of this service.
4391
4392 if (IS_POWER_DROP)
4393 {
7e4a7d39
A
4394 fDoNotPowerDown = false;
4395
6d2010ae
A
4396 // Ask for persmission to drop power state
4397 fMachineState = kIOPM_OurChangeTellClientsPowerDown;
7e4a7d39 4398 fOutOfBandParameter = kNotifyApps;
6d2010ae 4399 askChangeDown(fHeadNotePowerState);
7e4a7d39
A
4400 }
4401 else
4402 {
4403 // This service is raising power and parents are able to support the
4404 // new power state. However a parent may have already committed to
4405 // drop power, which might force this object to temporarily drop power.
4406 // This results in "oscillations" before the state machines converge
4407 // to a steady state.
4408 //
4409 // To prevent this, a child must make a power reservation against all
4410 // parents before raising power. If the reservation fails, indicating
4411 // that the child will be unable to sustain the higher power state,
4412 // then the child will signal the parent to adjust power, and the child
4413 // will defer its power change.
4414
7e4a7d39
A
4415 IOReturn ret;
4416
4417 // Reserve parent power necessary to achieve fHeadNotePowerState.
4418 ret = requestDomainPower( fHeadNotePowerState, kReserveDomainPower );
4419 if (ret != kIOReturnSuccess)
4420 {
4421 // Reservation failed, defer power rise.
6d2010ae 4422 fHeadNoteChangeFlags |= kIOPMNotDone;
7e4a7d39
A
4423 OurChangeFinish();
4424 return;
4425 }
6d2010ae
A
4426
4427 OurChangeTellCapabilityWillChange();
7e4a7d39
A
4428 }
4429}
4430
bd504ef0
A
4431//*********************************************************************************
4432// [private] requestDomainPowerApplier
4433//
4434// Call requestPowerDomainState() on all power parents.
7e4a7d39
A
4435//*********************************************************************************
4436
4437struct IOPMRequestDomainPowerContext {
4438 IOService * child; // the requesting child
4439 IOPMPowerFlags requestPowerFlags; // power flags requested by child
4440};
4441
4442static void
4443requestDomainPowerApplier(
4444 IORegistryEntry * entry,
4445 void * inContext )
4446{
4447 IOPowerConnection * connection;
4448 IOService * parent;
4449 IOPMRequestDomainPowerContext * context;
4450
4451 if ((connection = OSDynamicCast(IOPowerConnection, entry)) == 0)
4452 return;
4453 parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
4454 if (!parent)
4455 return;
4456
4457 assert(inContext);
4458 context = (IOPMRequestDomainPowerContext *) inContext;
4459
4460 if (connection->parentKnowsState() && connection->getReadyFlag())
4461 {
4462 parent->requestPowerDomainState(
4463 context->requestPowerFlags,
4464 connection,
4465 IOPMLowestState);
4466 }
4467
4468 parent->release();
4469}
4470
4471//*********************************************************************************
4472// [private] requestDomainPower
bd504ef0
A
4473//
4474// Called by a power child to broadcast its desired power state to all parents.
4475// If the child self-initiates a power change, it must call this function to
4476// allow its parents to adjust power state.
7e4a7d39
A
4477//*********************************************************************************
4478
4479IOReturn IOService::requestDomainPower(
6d2010ae
A
4480 IOPMPowerStateIndex ourPowerState,
4481 IOOptionBits options )
7e4a7d39 4482{
7e4a7d39 4483 IOPMPowerFlags requestPowerFlags;
6d2010ae 4484 IOPMPowerStateIndex maxPowerState;
7e4a7d39
A
4485 IOPMRequestDomainPowerContext context;
4486
4487 PM_ASSERT_IN_GATE();
4488 assert(ourPowerState < fNumberOfPowerStates);
4489 if (ourPowerState >= fNumberOfPowerStates)
4490 return kIOReturnBadArgument;
6d2010ae 4491 if (IS_PM_ROOT)
7e4a7d39
A
4492 return kIOReturnSuccess;
4493
bd504ef0 4494 // Fetch our input power flags for the requested power state.
7e4a7d39
A
4495 // Parent request is stated in terms of required power flags.
4496
316670eb 4497 requestPowerFlags = fPowerStates[ourPowerState].inputPowerFlags;
7e4a7d39
A
4498
4499 // Disregard the "previous request" for power reservation.
4500
4501 if (((options & kReserveDomainPower) == 0) &&
6d2010ae 4502 (fPreviousRequestPowerFlags == requestPowerFlags))
7e4a7d39
A
4503 {
4504 // skip if domain already knows our requirements
4505 goto done;
4506 }
6d2010ae 4507 fPreviousRequestPowerFlags = requestPowerFlags;
7e4a7d39 4508
bd504ef0 4509 // The results will be collected by fHeadNoteDomainTargetFlags
7e4a7d39
A
4510 context.child = this;
4511 context.requestPowerFlags = requestPowerFlags;
4512 fHeadNoteDomainTargetFlags = 0;
4513 applyToParents(requestDomainPowerApplier, &context, gIOPowerPlane);
4514
4515 if (options & kReserveDomainPower)
4516 {
4517 maxPowerState = fControllingDriver->maxCapabilityForDomainState(
4518 fHeadNoteDomainTargetFlags );
4519
39236c6e 4520 if (StateOrder(maxPowerState) < StateOrder(ourPowerState))
7e4a7d39 4521 {
6d2010ae 4522 PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
7e4a7d39
A
4523 getName(),
4524 (uint32_t) ourPowerState, (uint32_t) requestPowerFlags,
4525 (uint32_t) maxPowerState, (uint32_t) fHeadNoteDomainTargetFlags);
4526 return kIOReturnNoPower;
4527 }
4528 }
4529
4530done:
4531 return kIOReturnSuccess;
4532}
4533
4534//*********************************************************************************
4535// [private] OurSyncStart
4536//*********************************************************************************
4537
39236c6e 4538void IOService::OurSyncStart( void )
7e4a7d39
A
4539{
4540 PM_ASSERT_IN_GATE();
4541
6d2010ae 4542 if (fInitialPowerChange)
7e4a7d39
A
4543 return;
4544
6d2010ae
A
4545 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4546
4547 if (fHeadNoteChangeFlags & kIOPMNotDone)
4548 {
4549 OurChangeFinish();
4550 return;
4551 }
7e4a7d39 4552
6d2010ae
A
4553 if (fHeadNoteChangeFlags & kIOPMSyncTellPowerDown)
4554 {
4555 fDoNotPowerDown = false;
7e4a7d39 4556
6d2010ae
A
4557 // Ask for permission to drop power state
4558 fMachineState = kIOPM_SyncTellClientsPowerDown;
4559 fOutOfBandParameter = kNotifyApps;
4560 askChangeDown(fHeadNotePowerState);
4561 }
4562 else
4563 {
4564 // Only inform capability app and clients.
4565 tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange );
4566 }
7e4a7d39
A
4567}
4568
1c79356b 4569//*********************************************************************************
2d21ac55 4570// [private] OurChangeTellClientsPowerDown
1c79356b 4571//
6d2010ae
A
4572// All applications and kernel clients have acknowledged our permission to drop
4573// power. Here we notify them that we will lower the power and wait for acks.
1c79356b
A
4574//*********************************************************************************
4575
39236c6e 4576void IOService::OurChangeTellClientsPowerDown( void )
0b4e3aa0 4577{
39236c6e
A
4578 if(!IS_ROOT_DOMAIN)
4579 fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4580 else
4581 {
4582 fMachineState = kIOPM_OurChangeTellUserPMPolicyPowerDown;
4583 }
b0d623f7 4584 tellChangeDown1(fHeadNotePowerState);
0b4e3aa0
A
4585}
4586
39236c6e
A
4587//*********************************************************************************
4588// [private] OurChangeTellUserPMPolicyPowerDown
4589//
4590// All applications and kernel clients have acknowledged our permission to drop
4591// power. Here we notify power management policy in user-space and wait for acks
4592// one last time before we lower power
4593//*********************************************************************************
4594void IOService::OurChangeTellUserPMPolicyPowerDown ( void )
4595{
4596 fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4597 fOutOfBandParameter = kNotifyApps;
4598
4599 tellClientsWithResponse(kIOPMMessageLastCallBeforeSleep);
4600}
4601
0b4e3aa0 4602//*********************************************************************************
2d21ac55 4603// [private] OurChangeTellPriorityClientsPowerDown
0b4e3aa0 4604//
6d2010ae
A
4605// All applications and kernel clients have acknowledged our intention to drop
4606// power. Here we notify "priority" clients that we are lowering power.
0b4e3aa0
A
4607//*********************************************************************************
4608
39236c6e 4609void IOService::OurChangeTellPriorityClientsPowerDown( void )
1c79356b 4610{
2d21ac55 4611 fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
b0d623f7 4612 tellChangeDown2(fHeadNotePowerState);
1c79356b
A
4613}
4614
6d2010ae
A
4615//*********************************************************************************
4616// [private] OurChangeTellCapabilityWillChange
4617//
4618// Extra stage for root domain to notify apps and drivers about the
4619// system capability change when raising power state.
4620//*********************************************************************************
4621
39236c6e 4622void IOService::OurChangeTellCapabilityWillChange( void )
6d2010ae
A
4623{
4624 if (!IS_ROOT_DOMAIN)
4625 return OurChangeNotifyInterestedDriversWillChange();
4626
4627 tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange );
4628}
4629
1c79356b 4630//*********************************************************************************
2d21ac55 4631// [private] OurChangeNotifyInterestedDriversWillChange
1c79356b 4632//
6d2010ae
A
4633// All applications and kernel clients have acknowledged our power state change.
4634// Here we notify interested drivers pre-change.
1c79356b
A
4635//*********************************************************************************
4636
39236c6e 4637void IOService::OurChangeNotifyInterestedDriversWillChange( void )
1c79356b 4638{
6d2010ae 4639 IOPMrootDomain * rootDomain;
b0d623f7
A
4640 if ((rootDomain = getPMRootDomain()) == this)
4641 {
6d2010ae
A
4642 if (IS_POWER_DROP)
4643 {
4644 rootDomain->tracePoint( kIOPMTracePointSleepWillChangeInterests );
4645
4646 PMEventDetails *details = PMEventDetails::eventDetails(
4647 kIOPMEventTypeAppNotificationsFinished,
4648 NULL,
4649 100,
4650 kIOReturnSuccess);
39236c6e 4651 rootDomain->recordAndReleasePMEvent( details );
6d2010ae
A
4652 }
4653 else
4654 rootDomain->tracePoint( kIOPMTracePointWakeWillChangeInterests );
b0d623f7
A
4655 }
4656
6d2010ae 4657 notifyAll( kIOPM_OurChangeSetPowerState );
1c79356b
A
4658}
4659
1c79356b 4660//*********************************************************************************
2d21ac55 4661// [private] OurChangeSetPowerState
1c79356b 4662//
6d2010ae
A
4663// Instruct our controlling driver to program the hardware for the power state
4664// change. Wait for async completions.
1c79356b
A
4665//*********************************************************************************
4666
39236c6e 4667void IOService::OurChangeSetPowerState( void )
1c79356b 4668{
6d2010ae
A
4669 MS_PUSH( kIOPM_OurChangeWaitForPowerSettle );
4670 fMachineState = kIOPM_DriverThreadCallDone;
4671 fDriverCallReason = kDriverCallSetPowerState;
55e303ae 4672
6d2010ae
A
4673 if (notifyControllingDriver() == false)
4674 notifyControllingDriverDone();
1c79356b
A
4675}
4676
1c79356b 4677//*********************************************************************************
2d21ac55 4678// [private] OurChangeWaitForPowerSettle
1c79356b 4679//
6d2010ae
A
4680// Our controlling driver has completed the power state change we initiated.
4681// Wait for the driver specified settle time to expire.
1c79356b
A
4682//*********************************************************************************
4683
39236c6e 4684void IOService::OurChangeWaitForPowerSettle( void )
1c79356b 4685{
6d2010ae 4686 fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
7e4a7d39 4687 startSettleTimer();
1c79356b
A
4688}
4689
1c79356b 4690//*********************************************************************************
2d21ac55 4691// [private] OurChangeNotifyInterestedDriversDidChange
1c79356b 4692//
6d2010ae
A
4693// Power has settled on a power change we initiated. Here we notify
4694// all our interested drivers post-change.
1c79356b
A
4695//*********************************************************************************
4696
39236c6e 4697void IOService::OurChangeNotifyInterestedDriversDidChange( void )
1c79356b 4698{
6d2010ae
A
4699 IOPMrootDomain * rootDomain;
4700 if ((rootDomain = getPMRootDomain()) == this)
4701 {
4702 rootDomain->tracePoint( IS_POWER_DROP ?
4703 kIOPMTracePointSleepDidChangeInterests :
4704 kIOPMTracePointWakeDidChangeInterests );
4705 }
4706
4707 notifyAll( kIOPM_OurChangeTellCapabilityDidChange );
4708}
4709
4710//*********************************************************************************
4711// [private] OurChangeTellCapabilityDidChange
4712//
4713// For root domain to notify capability power-change.
4714//*********************************************************************************
4715
39236c6e 4716void IOService::OurChangeTellCapabilityDidChange( void )
6d2010ae
A
4717{
4718 if (!IS_ROOT_DOMAIN)
4719 return OurChangeFinish();
4720
4721 getPMRootDomain()->tracePoint( IS_POWER_DROP ?
4722 kIOPMTracePointSleepCapabilityClients :
4723 kIOPMTracePointWakeCapabilityClients );
4724
4725 tellSystemCapabilityChange( kIOPM_OurChangeFinish );
1c79356b
A
4726}
4727
1c79356b 4728//*********************************************************************************
2d21ac55 4729// [private] OurChangeFinish
1c79356b 4730//
6d2010ae 4731// Done with this self-induced power state change.
1c79356b
A
4732//*********************************************************************************
4733
39236c6e 4734void IOService::OurChangeFinish( void )
1c79356b
A
4735{
4736 all_done();
4737}
4738
7e4a7d39
A
4739// MARK: -
4740// MARK: Power Change Initiated by Parent
0b4e3aa0 4741
1c79356b 4742//*********************************************************************************
7e4a7d39 4743// [private] ParentChangeStart
1c79356b 4744//
7e4a7d39 4745// Here we begin the processing of a power change initiated by our parent.
1c79356b
A
4746//*********************************************************************************
4747
39236c6e 4748IOReturn IOService::ParentChangeStart( void )
1c79356b 4749{
7e4a7d39
A
4750 PM_ASSERT_IN_GATE();
4751 OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
4752
bd504ef0
A
4753 // Root power domain has transitioned to its max power state
4754 if ((fHeadNoteChangeFlags & (kIOPMDomainDidChange | kIOPMRootChangeUp)) ==
4755 (kIOPMDomainDidChange | kIOPMRootChangeUp))
b0d623f7 4756 {
bd504ef0
A
4757 // Restart the idle timer stopped by ParentChangeRootChangeDown()
4758 if (fIdleTimerPeriod && fIdleTimerStopped)
4759 {
4760 restartIdleTimer();
4761 }
4762 }
b0d623f7 4763
bd504ef0 4764 // Power domain is forcing us to lower power
39236c6e 4765 if ( StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState) )
bd504ef0 4766 {
6d2010ae 4767 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
1c79356b 4768
6d2010ae
A
4769 // Tell apps and kernel clients
4770 fInitialPowerChange = false;
4771 fMachineState = kIOPM_ParentChangeTellPriorityClientsPowerDown;
7e4a7d39
A
4772 tellChangeDown1(fHeadNotePowerState);
4773 return IOPMWillAckLater;
4774 }
4775
39236c6e
A
4776 // Power domain is allowing us to raise power up to fHeadNotePowerState
4777 if ( StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState) )
7e4a7d39 4778 {
39236c6e 4779 if ( StateOrder(fDesiredPowerState) > StateOrder(fCurrentPowerState) )
7e4a7d39 4780 {
39236c6e 4781 if ( StateOrder(fDesiredPowerState) < StateOrder(fHeadNotePowerState) )
7e4a7d39
A
4782 {
4783 // We power up, but not all the way
4784 fHeadNotePowerState = fDesiredPowerState;
4785 fHeadNotePowerArrayEntry = &fPowerStates[fDesiredPowerState];
4786 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
4787 }
4788 } else {
4789 // We don't need to change
4790 fHeadNotePowerState = fCurrentPowerState;
4791 fHeadNotePowerArrayEntry = &fPowerStates[fCurrentPowerState];
4792 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
4793 }
4794 }
4795
6d2010ae 4796 if ( fHeadNoteChangeFlags & kIOPMDomainDidChange )
7e4a7d39 4797 {
39236c6e 4798 if ( StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState) )
7e4a7d39 4799 {
6d2010ae
A
4800 PM_ACTION_2(actionPowerChangeStart,
4801 fHeadNotePowerState, &fHeadNoteChangeFlags);
7e4a7d39
A
4802
4803 // Parent did change up - start our change up
6d2010ae
A
4804 fInitialPowerChange = false;
4805 ParentChangeTellCapabilityWillChange();
7e4a7d39
A
4806 return IOPMWillAckLater;
4807 }
bd504ef0 4808 else if (fHeadNoteChangeFlags & kIOPMRootBroadcastFlags)
7e4a7d39 4809 {
bd504ef0
A
4810 // No need to change power state, but broadcast change
4811 // to our children.
7e4a7d39
A
4812 fMachineState = kIOPM_SyncNotifyDidChange;
4813 fDriverCallReason = kDriverCallInformPreChange;
4814 notifyChildren();
4815 return IOPMWillAckLater;
4816 }
4817 }
4818
4819 all_done();
4820 return IOPMAckImplied;
4821}
4822
bd504ef0
A
4823//******************************************************************************
4824// [private] ParentChangeRootChangeDown
4825//
4826// Root domain has finished the transition to the system sleep state. And all
4827// drivers in the power plane should have powered down. Cancel the idle timer,
4828// and also reset the device desire for those drivers that don't want power
4829// automatically restored on wake.
4830//******************************************************************************
4831
4832void IOService::ParentChangeRootChangeDown( void )
4833{
4834 // Always stop the idle timer before root power down
4835 if (fIdleTimerPeriod && !fIdleTimerStopped)
4836 {
4837 fIdleTimerStopped = true;
4838 if (fIdleTimer && thread_call_cancel(fIdleTimer))
4839 release();
4840 }
4841
4842 if (fResetPowerStateOnWake)
4843 {
4844 // Reset device desire down to the lowest power state.
4845 // Advisory tickle desire is intentionally untouched since
4846 // it has no effect until system is promoted to full wake.
4847
39236c6e 4848 if (fDeviceDesire != kPowerStateZero)
bd504ef0 4849 {
39236c6e
A
4850 updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
4851 computeDesiredState(kPowerStateZero, true);
bd504ef0
A
4852 PM_LOG1("%s: tickle desire removed\n", fName);
4853 }
4854
4855 // Invalidate tickle cache so the next tickle will issue a request
4856 IOLockLock(fActivityLock);
4857 fDeviceWasActive = false;
4858 fActivityTicklePowerState = kInvalidTicklePowerState;
4859 IOLockUnlock(fActivityLock);
4860
39236c6e 4861 fIdleTimerMinPowerState = kPowerStateZero;
bd504ef0
A
4862 }
4863 else if (fAdvisoryTickleUsed)
4864 {
4865 // Less aggressive mechanism to accelerate idle timer expiration
4866 // before system sleep. May not always allow the driver to wake
4867 // up from system sleep in the min power state.
4868
4869 AbsoluteTime now;
4870 uint64_t nsec;
4871 bool dropTickleDesire = false;
4872
4873 if (fIdleTimerPeriod && !fIdleTimerIgnored &&
39236c6e
A
4874 (fIdleTimerMinPowerState == kPowerStateZero) &&
4875 (fDeviceDesire != kPowerStateZero))
bd504ef0
A
4876 {
4877 IOLockLock(fActivityLock);
4878
4879 if (!fDeviceWasActive)
4880 {
4881 // No tickles since the last idle timer expiration.
4882 // Safe to drop the device desire to zero.
4883 dropTickleDesire = true;
4884 }
4885 else
4886 {
4887 // Was tickled since the last idle timer expiration,
4888 // but not in the last minute.
4889 clock_get_uptime(&now);
4890 SUB_ABSOLUTETIME(&now, &fDeviceActiveTimestamp);
4891 absolutetime_to_nanoseconds(now, &nsec);
4892 if (nsec >= kNoTickleCancelWindow)
4893 {
4894 dropTickleDesire = true;
4895 }
4896 }
4897
4898 if (dropTickleDesire)
4899 {
4900 // Force the next tickle to raise power state
4901 fDeviceWasActive = false;
4902 fActivityTicklePowerState = kInvalidTicklePowerState;
4903 }
4904
4905 IOLockUnlock(fActivityLock);
4906 }
4907
4908 if (dropTickleDesire)
4909 {
4910 // Advisory tickle desire is intentionally untouched since
4911 // it has no effect until system is promoted to full wake.
4912
39236c6e
A
4913 updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
4914 computeDesiredState(kPowerStateZero, true);
bd504ef0
A
4915 PM_LOG1("%s: tickle desire dropped\n", fName);
4916 }
4917 }
4918}
4919
7e4a7d39 4920//*********************************************************************************
6d2010ae 4921// [private] ParentChangeTellPriorityClientsPowerDown
7e4a7d39 4922//
6d2010ae
A
4923// All applications and kernel clients have acknowledged our intention to drop
4924// power. Here we notify "priority" clients that we are lowering power.
7e4a7d39
A
4925//*********************************************************************************
4926
39236c6e 4927void IOService::ParentChangeTellPriorityClientsPowerDown( void )
7e4a7d39 4928{
6d2010ae 4929 fMachineState = kIOPM_ParentChangeNotifyInterestedDriversWillChange;
7e4a7d39
A
4930 tellChangeDown2(fHeadNotePowerState);
4931}
4932
4933//*********************************************************************************
6d2010ae 4934// [private] ParentChangeTellCapabilityWillChange
7e4a7d39 4935//
6d2010ae
A
4936// All (legacy) applications and kernel clients have acknowledged, extra stage for
4937// root domain to notify apps and drivers about the system capability change.
7e4a7d39
A
4938//*********************************************************************************
4939
39236c6e 4940void IOService::ParentChangeTellCapabilityWillChange( void )
7e4a7d39 4941{
6d2010ae
A
4942 if (!IS_ROOT_DOMAIN)
4943 return ParentChangeNotifyInterestedDriversWillChange();
7e4a7d39 4944
6d2010ae 4945 tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange );
7e4a7d39
A
4946}
4947
4948//*********************************************************************************
6d2010ae 4949// [private] ParentChangeNotifyInterestedDriversWillChange
7e4a7d39 4950//
6d2010ae
A
4951// All applications and kernel clients have acknowledged our power state change.
4952// Here we notify interested drivers pre-change.
1c79356b
A
4953//*********************************************************************************
4954
39236c6e 4955void IOService::ParentChangeNotifyInterestedDriversWillChange( void )
1c79356b 4956{
6d2010ae
A
4957 notifyAll( kIOPM_ParentChangeSetPowerState );
4958}
1c79356b 4959
6d2010ae
A
4960//*********************************************************************************
4961// [private] ParentChangeSetPowerState
4962//
4963// Instruct our controlling driver to program the hardware for the power state
4964// change. Wait for async completions.
4965//*********************************************************************************
4966
39236c6e 4967void IOService::ParentChangeSetPowerState( void )
6d2010ae
A
4968{
4969 MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle );
4970 fMachineState = kIOPM_DriverThreadCallDone;
4971 fDriverCallReason = kDriverCallSetPowerState;
4972
4973 if (notifyControllingDriver() == false)
4974 notifyControllingDriverDone();
1c79356b
A
4975}
4976
1c79356b 4977//*********************************************************************************
6d2010ae 4978// [private] ParentChangeWaitForPowerSettle
1c79356b 4979//
6d2010ae
A
4980// Our controlling driver has completed the power state change initiated by our
4981// parent. Wait for the driver specified settle time to expire.
1c79356b
A
4982//*********************************************************************************
4983
39236c6e 4984void IOService::ParentChangeWaitForPowerSettle( void )
1c79356b 4985{
6d2010ae 4986 fMachineState = kIOPM_ParentChangeNotifyInterestedDriversDidChange;
7e4a7d39 4987 startSettleTimer();
1c79356b
A
4988}
4989
1c79356b 4990//*********************************************************************************
6d2010ae
A
4991// [private] ParentChangeNotifyInterestedDriversDidChange
4992//
4993// Power has settled on a power change initiated by our parent. Here we notify
4994// all our interested drivers post-change.
4995//*********************************************************************************
4996
39236c6e 4997void IOService::ParentChangeNotifyInterestedDriversDidChange( void )
6d2010ae
A
4998{
4999 notifyAll( kIOPM_ParentChangeTellCapabilityDidChange );
5000}
5001
5002//*********************************************************************************
5003// [private] ParentChangeTellCapabilityDidChange
1c79356b 5004//
6d2010ae 5005// For root domain to notify capability power-change.
1c79356b
A
5006//*********************************************************************************
5007
39236c6e 5008void IOService::ParentChangeTellCapabilityDidChange( void )
1c79356b 5009{
6d2010ae
A
5010 if (!IS_ROOT_DOMAIN)
5011 return ParentChangeAcknowledgePowerChange();
5012
5013 tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange );
1c79356b
A
5014}
5015
1c79356b 5016//*********************************************************************************
b0d623f7 5017// [private] ParentAcknowledgePowerChange
1c79356b 5018//
6d2010ae 5019// Acknowledge our power parent that our power change is done.
1c79356b
A
5020//*********************************************************************************
5021
39236c6e 5022void IOService::ParentChangeAcknowledgePowerChange( void )
1c79356b 5023{
2d21ac55
A
5024 IORegistryEntry * nub;
5025 IOService * parent;
5026
b0d623f7 5027 nub = fHeadNoteParentConnection;
55e303ae 5028 nub->retain();
1c79356b 5029 all_done();
0b4e3aa0 5030 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
2d21ac55 5031 if ( parent )
55e303ae 5032 {
0b4e3aa0
A
5033 parent->acknowledgePowerChange((IOService *)nub);
5034 parent->release();
5035 }
5036 nub->release();
1c79356b
A
5037}
5038
6d2010ae
A
5039// MARK: -
5040// MARK: Ack and Settle timers
5041
1c79356b 5042//*********************************************************************************
6d2010ae 5043// [private] settleTimerExpired
1c79356b 5044//
6d2010ae
A
5045// Power has settled after our last change. Notify interested parties that
5046// there is a new power state.
1c79356b
A
5047//*********************************************************************************
5048
6d2010ae 5049void IOService::settleTimerExpired( void )
1c79356b 5050{
6d2010ae
A
5051 fSettleTimeUS = 0;
5052 gIOPMWorkQueue->signalWorkAvailable();
1c79356b
A
5053}
5054
1c79356b 5055//*********************************************************************************
6d2010ae 5056// settle_timer_expired
1c79356b 5057//
6d2010ae 5058// Holds a retain while the settle timer callout is in flight.
1c79356b
A
5059//*********************************************************************************
5060
7e4a7d39
A
5061static void
5062settle_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
1c79356b 5063{
7e4a7d39
A
5064 IOService * me = (IOService *) arg0;
5065
6d2010ae 5066 if (gIOPMWorkLoop && gIOPMWorkQueue)
7e4a7d39
A
5067 {
5068 gIOPMWorkLoop->runAction(
5069 OSMemberFunctionCast(IOWorkLoop::Action, me, &IOService::settleTimerExpired),
5070 me);
7e4a7d39
A
5071 }
5072 me->release();
5073}
5074
5075//*********************************************************************************
5076// [private] startSettleTimer
5077//
5078// Calculate a power-settling delay in microseconds and start a timer.
5079//*********************************************************************************
5080
5081void IOService::startSettleTimer( void )
5082{
bd504ef0
A
5083#if NOT_USEFUL
5084 // This function is broken and serves no useful purpose since it never
5085 // updates fSettleTimeUS to a non-zero value to stall the state machine,
5086 // yet it starts a delay timer. It appears no driver relies on a delay
5087 // from settleUpTime and settleDownTime in the power state table.
5088
7e4a7d39 5089 AbsoluteTime deadline;
39236c6e
A
5090 IOPMPowerStateIndex stateIndex;
5091 IOPMPowerStateIndex currentOrder, newOrder, i;
7e4a7d39
A
5092 uint32_t settleTime = 0;
5093 boolean_t pending;
2d21ac55
A
5094
5095 PM_ASSERT_IN_GATE();
1c79356b 5096
39236c6e
A
5097 currentOrder = StateOrder(fCurrentPowerState);
5098 newOrder = StateOrder(fHeadNotePowerState);
5099
5100 i = currentOrder;
55e303ae 5101
7e4a7d39 5102 // lowering power
39236c6e 5103 if ( newOrder < currentOrder )
55e303ae 5104 {
39236c6e 5105 while ( i > newOrder )
55e303ae 5106 {
39236c6e
A
5107 stateIndex = fPowerStates[i].stateOrderToIndex;
5108 settleTime += (uint32_t) fPowerStates[stateIndex].settleDownTime;
1c79356b
A
5109 i--;
5110 }
5111 }
5112
7e4a7d39 5113 // raising power
39236c6e 5114 if ( newOrder > currentOrder )
55e303ae 5115 {
39236c6e 5116 while ( i < newOrder )
55e303ae 5117 {
39236c6e
A
5118 stateIndex = fPowerStates[i+1].stateOrderToIndex;
5119 settleTime += (uint32_t) fPowerStates[stateIndex].settleUpTime;
1c79356b
A
5120 i++;
5121 }
5122 }
5123
7e4a7d39
A
5124 if (settleTime)
5125 {
5126 retain();
5127 clock_interval_to_deadline(settleTime, kMicrosecondScale, &deadline);
5128 pending = thread_call_enter_delayed(fSettleTimer, deadline);
5129 if (pending) release();
5130 }
bd504ef0 5131#endif
1c79356b
A
5132}
5133
5134//*********************************************************************************
7e4a7d39 5135// [private] ackTimerTick
1c79356b
A
5136//
5137// The acknowledgement timeout periodic timer has ticked.
5138// If we are awaiting acks for a power change notification,
5139// we decrement the timer word of each interested driver which hasn't acked.
5140// If a timer word becomes zero, we pretend the driver aknowledged.
5141// If we are waiting for the controlling driver to change the power
5142// state of the hardware, we decrement its timer word, and if it becomes
5143// zero, we pretend the driver acknowledged.
2d21ac55
A
5144//
5145// Returns true if the timer tick made it possible to advance to the next
5146// machine state, false otherwise.
1c79356b
A
5147//*********************************************************************************
5148
b0d623f7 5149#ifndef __LP64__
1c79356b
A
5150void IOService::ack_timer_ticked ( void )
5151{
2d21ac55
A
5152 assert(false);
5153}
b0d623f7 5154#endif /* !__LP64__ */
1c79356b 5155
2d21ac55
A
5156bool IOService::ackTimerTick( void )
5157{
5158 IOPMinformee * nextObject;
5159 bool done = false;
1c79356b 5160
2d21ac55
A
5161 PM_ASSERT_IN_GATE();
5162 switch (fMachineState) {
55e303ae 5163 case kIOPM_OurChangeWaitForPowerSettle:
6d2010ae 5164 case kIOPM_ParentChangeWaitForPowerSettle:
2d21ac55
A
5165 // are we waiting for controlling driver to acknowledge?
5166 if ( fDriverTimer > 0 )
5167 {
5168 // yes, decrement timer tick
5169 fDriverTimer--;
5170 if ( fDriverTimer == 0 )
55e303ae 5171 {
2d21ac55
A
5172 // controlling driver is tardy
5173 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
5174 OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
5175 setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
5176 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
39236c6e 5177 fName, OBFUSCATE(this), fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
2d21ac55 5178
6d2010ae
A
5179#if LOG_SETPOWER_TIMES
5180 PMEventDetails *details = PMEventDetails::eventDetails(
5181 kIOPMEventTypeSetPowerStateDelayed, // type
5182 fName, // who
5183 (uintptr_t)this, // owner unique
5184 NULL, // interest name
5185 (uint8_t)getPowerState(), // old
5186 0, // new
5187 kIOReturnTimeout, // result
5188 NS_TO_US(nsec)); // usec completion time
5189
39236c6e 5190 getPMRootDomain()->recordAndReleasePMEvent( details );
6d2010ae
A
5191#endif
5192
2d21ac55
A
5193 if (gIOKitDebug & kIOLogDebugPower)
5194 {
5195 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
b0d623f7 5196 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
2d21ac55
A
5197 }
5198 else
5199 {
5200 // Unblock state machine and pretend driver has acked.
5201 done = true;
5202 }
55e303ae
A
5203 } else {
5204 // still waiting, set timer again
1c79356b 5205 start_ack_timer();
1c79356b
A
5206 }
5207 }
1c79356b
A
5208 break;
5209
6d2010ae 5210 case kIOPM_NotifyChildrenStart:
55e303ae 5211 // are we waiting for interested parties to acknowledge?
2d21ac55 5212 if ( fHeadNotePendingAcks != 0 )
55e303ae
A
5213 {
5214 // yes, go through the list of interested drivers
2d21ac55 5215 nextObject = fInterestedDrivers->firstInList();
55e303ae 5216 // and check each one
2d21ac55 5217 while ( nextObject != NULL )
55e303ae 5218 {
2d21ac55 5219 if ( nextObject->timer > 0 )
55e303ae 5220 {
2d21ac55 5221 nextObject->timer--;
55e303ae 5222 // this one should have acked by now
2d21ac55 5223 if ( nextObject->timer == 0 )
55e303ae 5224 {
2d21ac55
A
5225 uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
5226 OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
5227 nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
5228 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
5229 nextObject->whatObject->getName(),
5230 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
39236c6e 5231 OBFUSCATE(nextObject->whatObject), fName, fCurrentPowerState, fHeadNotePowerState,
2d21ac55
A
5232 NS_TO_MS(nsec));
5233
6d2010ae
A
5234#if LOG_SETPOWER_TIMES
5235 uint16_t logType = (fDriverCallReason == kDriverCallInformPreChange)
5236 ? kIOPMEventTypePSWillChangeTo
5237 : kIOPMEventTypePSDidChangeTo;
5238
5239 PMEventDetails *details = PMEventDetails::eventDetails(
5240 logType, // type
5241 fName, // who
5242 (uintptr_t)this, // owner unique
5243 nextObject->whatObject->getName(), // interest name
5244 (uint8_t)fCurrentPowerState, // old
5245 (uint8_t)fHeadNotePowerState, // new
5246 kIOReturnTimeout, // result
5247 NS_TO_US(nsec)); // usec completion time
5248
39236c6e 5249 getPMRootDomain()->recordAndReleasePMEvent( details );
6d2010ae
A
5250#endif
5251
2d21ac55
A
5252 // Pretend driver has acked.
5253 fHeadNotePendingAcks--;
1c79356b
A
5254 }
5255 }
2d21ac55 5256 nextObject = fInterestedDrivers->nextInList(nextObject);
1c79356b 5257 }
55e303ae
A
5258
5259 // is that the last?
2d21ac55 5260 if ( fHeadNotePendingAcks == 0 )
55e303ae 5261 {
55e303ae 5262 // yes, we can continue
2d21ac55 5263 done = true;
55e303ae
A
5264 } else {
5265 // no, set timer again
1c79356b 5266 start_ack_timer();
1c79356b 5267 }
1c79356b
A
5268 }
5269 break;
5270
6d2010ae 5271 // TODO: aggreggate this
55e303ae 5272 case kIOPM_OurChangeTellClientsPowerDown:
39236c6e 5273 case kIOPM_OurChangeTellUserPMPolicyPowerDown:
55e303ae 5274 case kIOPM_OurChangeTellPriorityClientsPowerDown:
55e303ae 5275 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
6d2010ae
A
5276 case kIOPM_ParentChangeTellPriorityClientsPowerDown:
5277 case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
5278 case kIOPM_SyncTellClientsPowerDown:
5279 case kIOPM_SyncTellPriorityClientsPowerDown:
5280 case kIOPM_SyncNotifyWillChange:
5281 case kIOPM_TellCapabilityChangeDone:
2d21ac55
A
5282 // apps didn't respond in time
5283 cleanClientResponses(true);
5284 OUR_PMLog(kPMLogClientTardy, 0, 1);
593a1d5f 5285 // tardy equates to approval
2d21ac55 5286 done = true;
1c79356b 5287 break;
2d21ac55 5288
1c79356b 5289 default:
6d2010ae 5290 PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
2d21ac55 5291 getName(), fMachineState);
1c79356b
A
5292 break;
5293 }
2d21ac55 5294 return done;
1c79356b
A
5295}
5296
39236c6e
A
5297//*********************************************************************************
5298// [private] start_watchdog_timer
5299//*********************************************************************************
5300void IOService::start_watchdog_timer( void )
5301{
5302 AbsoluteTime deadline;
5303 boolean_t pending;
5304
5305 if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug) ||
5306 (getPMRootDomain()->sleepWakeDebugIsWdogEnabled() == false))
5307 return;
5308
5309 if (thread_call_isactive(fWatchdogTimer)) return;
5310
5311 clock_interval_to_deadline(WATCHDOG_TIMER_PERIOD, kSecondScale, &deadline);
5312
5313 retain();
5314 pending = thread_call_enter_delayed(fWatchdogTimer, deadline);
5315 if (pending) release();
5316
5317}
5318
5319//*********************************************************************************
5320// [private] stop_watchdog_timer
5321// Returns true if watchdog was enabled and stopped now
5322//*********************************************************************************
5323
5324bool IOService::stop_watchdog_timer( void )
5325{
5326 boolean_t pending;
5327
5328 if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug) ||
5329 (getPMRootDomain()->sleepWakeDebugIsWdogEnabled() == false))
5330 return false;
5331
5332 pending = thread_call_cancel(fWatchdogTimer);
5333 if (pending) release();
5334
5335 return pending;
5336}
5337
5338//*********************************************************************************
5339// reset_watchdog_timer
5340//*********************************************************************************
5341
5342void IOService::reset_watchdog_timer( void )
5343{
5344 if (stop_watchdog_timer())
5345 start_watchdog_timer();
5346}
5347
5348
5349//*********************************************************************************
5350// [static] watchdog_timer_expired
5351//
5352// Inside PM work loop's gate.
5353//*********************************************************************************
5354
5355void
5356IOService::watchdog_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5357{
5358 IOService * me = (IOService *) arg0;
5359
5360
5361 gIOPMWatchDogThread = current_thread();
5362 getPMRootDomain()->sleepWakeDebugTrig(true);
5363 gIOPMWatchDogThread = 0;
5364 me->release();
5365
5366 return ;
5367}
5368
5369
1c79356b 5370//*********************************************************************************
2d21ac55 5371// [private] start_ack_timer
1c79356b
A
5372//*********************************************************************************
5373
39236c6e 5374void IOService::start_ack_timer( void )
1c79356b 5375{
2d21ac55 5376 start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
1c79356b
A
5377}
5378
2d21ac55
A
5379void IOService::start_ack_timer ( UInt32 interval, UInt32 scale )
5380{
39236c6e
A
5381 AbsoluteTime deadline;
5382 boolean_t pending;
2d21ac55
A
5383
5384 clock_interval_to_deadline(interval, scale, &deadline);
5385
39236c6e 5386 retain();
2d21ac55 5387 pending = thread_call_enter_delayed(fAckTimer, deadline);
39236c6e
A
5388 if (pending) release();
5389
5390 // Stop watchdog if ack is delayed by more than a sec
5391 if (interval * scale > kSecondScale) {
5392 stop_watchdog_timer();
5393 }
2d21ac55 5394}
1c79356b
A
5395
5396//*********************************************************************************
2d21ac55 5397// [private] stop_ack_timer
1c79356b
A
5398//*********************************************************************************
5399
39236c6e 5400void IOService::stop_ack_timer( void )
1c79356b 5401{
39236c6e 5402 boolean_t pending;
1c79356b 5403
2d21ac55 5404 pending = thread_call_cancel(fAckTimer);
39236c6e
A
5405 if (pending) release();
5406
5407 start_watchdog_timer();
2d21ac55 5408}
1c79356b
A
5409
5410//*********************************************************************************
b0d623f7 5411// [static] actionAckTimerExpired
1c79356b 5412//
2d21ac55 5413// Inside PM work loop's gate.
1c79356b
A
5414//*********************************************************************************
5415
2d21ac55 5416IOReturn
39236c6e
A
5417IOService::actionAckTimerExpired(
5418 OSObject * target,
5419 void * arg0, void * arg1,
5420 void * arg2, void * arg3 )
1c79356b 5421{
39236c6e
A
5422 IOService * me = (IOService *) target;
5423 bool done;
1c79356b 5424
39236c6e
A
5425 // done will be true if the timer tick unblocks the machine state,
5426 // otherwise no need to signal the work loop.
1c79356b 5427
39236c6e
A
5428 done = me->ackTimerTick();
5429 if (done && gIOPMWorkQueue)
5430 {
5431 gIOPMWorkQueue->signalWorkAvailable();
5432 me->start_watchdog_timer();
5433 }
1c79356b 5434
39236c6e 5435 return kIOReturnSuccess;
2d21ac55 5436}
1c79356b
A
5437
5438//*********************************************************************************
2d21ac55 5439// ack_timer_expired
1c79356b 5440//
2d21ac55 5441// Thread call function. Holds a retain while the callout is in flight.
1c79356b
A
5442//*********************************************************************************
5443
2d21ac55 5444void
39236c6e 5445IOService::ack_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
1c79356b 5446{
2d21ac55 5447 IOService * me = (IOService *) arg0;
55e303ae 5448
2d21ac55
A
5449 if (gIOPMWorkLoop)
5450 {
5451 gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
5452 }
5453 me->release();
1c79356b
A
5454}
5455
6d2010ae
A
5456// MARK: -
5457// MARK: Client Messaging
1c79356b 5458
1c79356b 5459//*********************************************************************************
6d2010ae 5460// [private] tellSystemCapabilityChange
1c79356b
A
5461//*********************************************************************************
5462
6d2010ae 5463void IOService::tellSystemCapabilityChange( uint32_t nextMS )
1c79356b 5464{
6d2010ae
A
5465 MS_PUSH( nextMS );
5466 fMachineState = kIOPM_TellCapabilityChangeDone;
5467 fOutOfBandMessage = kIOMessageSystemCapabilityChange;
2d21ac55 5468
6d2010ae
A
5469 if (fIsPreChange)
5470 {
5471 // Notify app first on pre-change.
5472 fOutOfBandParameter = kNotifyCapabilityChangeApps;
5473 }
5474 else
5475 {
5476 // Notify kernel clients first on post-change.
5477 fOutOfBandParameter = kNotifyCapabilityChangePriority;
5478 }
1c79356b 5479
6d2010ae 5480 tellClientsWithResponse( fOutOfBandMessage );
1c79356b
A
5481}
5482
1c79356b 5483//*********************************************************************************
b0d623f7 5484// [public] askChangeDown
1c79356b
A
5485//
5486// Ask registered applications and kernel clients if we can change to a lower
5487// power state.
5488//
5489// Subclass can override this to send a different message type. Parameter is
5490// the destination state number.
5491//
5492// Return true if we don't have to wait for acknowledgements
5493//*********************************************************************************
5494
39236c6e 5495bool IOService::askChangeDown( unsigned long stateNum )
1c79356b 5496{
2d21ac55 5497 return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
1c79356b
A
5498}
5499
0b4e3aa0 5500//*********************************************************************************
b0d623f7 5501// [private] tellChangeDown1
0b4e3aa0
A
5502//
5503// Notify registered applications and kernel clients that we are definitely
5504// dropping power.
5505//
5506// Return true if we don't have to wait for acknowledgements
5507//*********************************************************************************
5508
39236c6e 5509bool IOService::tellChangeDown1( unsigned long stateNum )
0b4e3aa0 5510{
2d21ac55 5511 fOutOfBandParameter = kNotifyApps;
0b4e3aa0
A
5512 return tellChangeDown(stateNum);
5513}
5514
0b4e3aa0 5515//*********************************************************************************
b0d623f7 5516// [private] tellChangeDown2
0b4e3aa0
A
5517//
5518// Notify priority clients that we are definitely dropping power.
5519//
5520// Return true if we don't have to wait for acknowledgements
5521//*********************************************************************************
5522
39236c6e 5523bool IOService::tellChangeDown2( unsigned long stateNum )
0b4e3aa0 5524{
2d21ac55 5525 fOutOfBandParameter = kNotifyPriority;
0b4e3aa0
A
5526 return tellChangeDown(stateNum);
5527}
5528
1c79356b 5529//*********************************************************************************
b0d623f7 5530// [public] tellChangeDown
1c79356b
A
5531//
5532// Notify registered applications and kernel clients that we are definitely
5533// dropping power.
5534//
5535// Subclass can override this to send a different message type. Parameter is
5536// the destination state number.
5537//
5538// Return true if we don't have to wait for acknowledgements
5539//*********************************************************************************
5540
39236c6e 5541bool IOService::tellChangeDown( unsigned long stateNum )
1c79356b 5542{
2d21ac55
A
5543 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
5544}
5545
5546//*********************************************************************************
5547// cleanClientResponses
5548//
5549//*********************************************************************************
5550
39236c6e 5551static void logAppTimeouts( OSObject * object, void * arg )
2d21ac55 5552{
b0d623f7
A
5553 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5554 OSObject * flag;
5555 unsigned int clientIndex;
39236c6e
A
5556 int pid = -1;
5557 char name[128];
2d21ac55 5558
b0d623f7
A
5559 if (OSDynamicCast(_IOServiceInterestNotifier, object))
5560 {
5561 // Discover the 'counter' value or index assigned to this client
5562 // when it was notified, by searching for the array index of the
5563 // client in an array holding the cached interested clients.
5564
5565 clientIndex = context->notifyClients->getNextIndexOfObject(object, 0);
5566
5567 if ((clientIndex != (unsigned int) -1) &&
6d2010ae 5568 (flag = context->responseArray->getObject(clientIndex)) &&
b0d623f7 5569 (flag != kOSBooleanTrue))
2d21ac55 5570 {
316670eb
A
5571 OSNumber *clientID = copyClientIDForNotification(object, context);
5572
39236c6e 5573 name[0] = '\0';
316670eb 5574 if (clientID) {
39236c6e
A
5575 pid = clientID->unsigned32BitValue();
5576 proc_name(pid, name, sizeof(name));
316670eb
A
5577 clientID->release();
5578 }
5579
39236c6e 5580 PM_ERROR(context->errorLog, pid, name);
b0d623f7
A
5581
5582 // TODO: record message type if possible
5583 IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
5584 gIOPMStatsApplicationResponseTimedOut,
39236c6e 5585 name, 0, (30*1000), pid);
b0d623f7 5586
2d21ac55 5587 }
2d21ac55 5588 }
1c79356b
A
5589}
5590
39236c6e 5591void IOService::cleanClientResponses( bool logErrors )
2d21ac55 5592{
6d2010ae
A
5593 if (logErrors && fResponseArray)
5594 {
2d21ac55
A
5595 switch ( fOutOfBandParameter ) {
5596 case kNotifyApps:
6d2010ae
A
5597 case kNotifyCapabilityChangeApps:
5598 if (fNotifyClientArray)
5599 {
5600 IOPMInterestContext context;
5601
5602 context.responseArray = fResponseArray;
5603 context.notifyClients = fNotifyClientArray;
5604 context.serialNumber = fSerialNumber;
5605 context.messageType = kIOMessageCopyClientID;
5606 context.notifyType = kNotifyApps;
5607 context.isPreChange = fIsPreChange;
5608 context.enableTracing = false;
5609 context.us = this;
5610 context.maxTimeRequested = 0;
5611 context.stateNumber = fHeadNotePowerState;
5612 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
5613 context.changeFlags = fHeadNoteChangeFlags;
39236c6e 5614 context.errorLog = "PM notification timeout (pid %d, %s)\n";
6d2010ae
A
5615
5616 applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &context);
5617 }
5618 break;
5619
2d21ac55 5620 default:
6d2010ae
A
5621 // kNotifyPriority, kNotifyCapabilityChangePriority
5622 // TODO: identify the priority client that has not acked
5623 PM_ERROR("PM priority notification timeout\n");
5624 if (gIOKitDebug & kIOLogDebugPower)
5625 {
5626 panic("PM priority notification timeout");
5627 }
2d21ac55
A
5628 break;
5629 }
5630 }
5631
b0d623f7 5632 if (fResponseArray)
2d21ac55 5633 {
2d21ac55
A
5634 fResponseArray->release();
5635 fResponseArray = NULL;
5636 }
b0d623f7
A
5637 if (fNotifyClientArray)
5638 {
5639 fNotifyClientArray->release();
5640 fNotifyClientArray = NULL;
5641 }
2d21ac55 5642}
1c79356b
A
5643
5644//*********************************************************************************
b0d623f7 5645// [protected] tellClientsWithResponse
1c79356b
A
5646//
5647// Notify registered applications and kernel clients that we are definitely
5648// dropping power.
5649//
5650// Return true if we don't have to wait for acknowledgements
5651//*********************************************************************************
5652
39236c6e 5653bool IOService::tellClientsWithResponse( int messageType )
1c79356b 5654{
b0d623f7 5655 IOPMInterestContext context;
6d2010ae 5656 bool isRootDomain = IS_ROOT_DOMAIN;
2d21ac55
A
5657
5658 PM_ASSERT_IN_GATE();
b0d623f7
A
5659 assert( fResponseArray == NULL );
5660 assert( fNotifyClientArray == NULL );
1c79356b 5661
39236c6e
A
5662 if(messageType == (int)kIOPMMessageLastCallBeforeSleep)
5663 RD_LOG("tellClientsWithResponse( kIOPMMessageLastCallBeforeSleep, %d )\n",
5664 fOutOfBandParameter);
5665 else
5666 RD_LOG("tellClientsWithResponse( %s, %d )\n",
5667 getIOMessageString(messageType), fOutOfBandParameter);
6d2010ae 5668
2d21ac55 5669 fResponseArray = OSArray::withCapacity( 1 );
b0d623f7
A
5670 if (!fResponseArray)
5671 goto exit;
5672
5673 fResponseArray->setCapacityIncrement(8);
6d2010ae
A
5674 if (++fSerialNumber == 0)
5675 fSerialNumber++;
b0d623f7 5676
6d2010ae 5677 context.responseArray = fResponseArray;
b0d623f7
A
5678 context.notifyClients = 0;
5679 context.serialNumber = fSerialNumber;
6d2010ae
A
5680 context.messageType = messageType;
5681 context.notifyType = fOutOfBandParameter;
5682 context.isPreChange = fIsPreChange;
5683 context.enableTracing = false;
b0d623f7
A
5684 context.us = this;
5685 context.maxTimeRequested = 0;
5686 context.stateNumber = fHeadNotePowerState;
5687 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6d2010ae
A
5688 context.changeFlags = fHeadNoteChangeFlags;
5689 context.messageFilter = (isRootDomain) ?
5690 OSMemberFunctionCast(
5691 IOPMMessageFilter,
5692 this,
5693 &IOPMrootDomain::systemMessageFilter) : 0;
0b4e3aa0 5694
2d21ac55 5695 switch ( fOutOfBandParameter ) {
0b4e3aa0 5696 case kNotifyApps:
b0d623f7
A
5697 applyToInterested( gIOAppPowerStateInterest,
5698 pmTellAppWithResponse, (void *) &context );
6d2010ae
A
5699
5700 if (isRootDomain &&
5701 (fMachineState != kIOPM_OurChangeTellClientsPowerDown) &&
39236c6e
A
5702 (fMachineState != kIOPM_SyncTellClientsPowerDown) &&
5703 (context.messageType != kIOPMMessageLastCallBeforeSleep))
6d2010ae
A
5704 {
5705 // Notify capability app for tellChangeDown1()
5706 // but not for askChangeDown().
5707 context.notifyType = kNotifyCapabilityChangeApps;
5708 context.messageType = kIOMessageSystemCapabilityChange;
5709 applyToInterested( gIOAppPowerStateInterest,
5710 pmTellCapabilityAppWithResponse, (void *) &context );
5711 context.notifyType = fOutOfBandParameter;
5712 context.messageType = messageType;
5713 }
316670eb 5714 context.maxTimeRequested = k30Seconds;
b0d623f7
A
5715
5716 applyToInterested( gIOGeneralInterest,
5717 pmTellClientWithResponse, (void *) &context );
6d2010ae
A
5718
5719 fNotifyClientArray = context.notifyClients;
0b4e3aa0 5720 break;
b0d623f7 5721
0b4e3aa0 5722 case kNotifyPriority:
6d2010ae 5723 context.enableTracing = isRootDomain;
b0d623f7
A
5724 applyToInterested( gIOPriorityPowerStateInterest,
5725 pmTellClientWithResponse, (void *) &context );
6d2010ae
A
5726
5727 if (isRootDomain)
5728 {
5729 // Notify capability clients for tellChangeDown2().
5730 context.notifyType = kNotifyCapabilityChangePriority;
5731 context.messageType = kIOMessageSystemCapabilityChange;
5732 applyToInterested( gIOPriorityPowerStateInterest,
5733 pmTellCapabilityClientWithResponse, (void *) &context );
5734 }
5735 break;
5736
5737 case kNotifyCapabilityChangeApps:
5738 applyToInterested( gIOAppPowerStateInterest,
5739 pmTellCapabilityAppWithResponse, (void *) &context );
5740 fNotifyClientArray = context.notifyClients;
316670eb 5741 context.maxTimeRequested = k30Seconds;
6d2010ae
A
5742 break;
5743
5744 case kNotifyCapabilityChangePriority:
5745 applyToInterested( gIOPriorityPowerStateInterest,
5746 pmTellCapabilityClientWithResponse, (void *) &context );
0b4e3aa0
A
5747 break;
5748 }
b0d623f7 5749
55e303ae 5750 // do we have to wait for somebody?
2d21ac55 5751 if ( !checkForDone() )
55e303ae 5752 {
b0d623f7 5753 OUR_PMLog(kPMLogStartAckTimer, context.maxTimeRequested, 0);
6d2010ae
A
5754 if (context.enableTracing)
5755 getPMRootDomain()->traceDetail( context.maxTimeRequested / 1000 );
39236c6e 5756 start_ack_timer( context.maxTimeRequested / 1000, kMillisecondScale );
1c79356b
A
5757 return false;
5758 }
2d21ac55 5759
b0d623f7 5760exit:
55e303ae 5761 // everybody responded
b0d623f7
A
5762 if (fResponseArray)
5763 {
5764 fResponseArray->release();
5765 fResponseArray = NULL;
5766 }
5767 if (fNotifyClientArray)
5768 {
5769 fNotifyClientArray->release();
5770 fNotifyClientArray = NULL;
5771 }
5772
1c79356b
A
5773 return true;
5774}
5775
1c79356b 5776//*********************************************************************************
2d21ac55 5777// [static private] pmTellAppWithResponse
1c79356b
A
5778//
5779// We send a message to an application, and we expect a response, so we compute a
5780// cookie we can identify the response with.
5781//*********************************************************************************
2d21ac55 5782
39236c6e 5783void IOService::pmTellAppWithResponse( OSObject * object, void * arg )
1c79356b 5784{
6d2010ae 5785 IOPMInterestContext * context = (IOPMInterestContext *) arg;
b0d623f7 5786 IOServicePM * pwrMgt = context->us->pwrMgt;
6d2010ae 5787 uint32_t msgIndex, msgRef, msgType;
316670eb
A
5788 OSNumber *clientID = NULL;
5789 proc_t proc = NULL;
5790 boolean_t proc_suspended = FALSE;
6d2010ae 5791#if LOG_APP_RESPONSE_TIMES
b0d623f7 5792 AbsoluteTime now;
6d2010ae 5793#endif
91447636 5794
b0d623f7 5795 if (!OSDynamicCast(_IOServiceInterestNotifier, object))
6d2010ae
A
5796 return;
5797
316670eb
A
5798 if (context->us == getPMRootDomain())
5799 {
5800 if ((clientID = copyClientIDForNotification(object, context)))
5801 {
5802 uint32_t clientPID = clientID->unsigned32BitValue();
5803 clientID->release();
5804 proc = proc_find(clientPID);
5805
5806 if (proc)
5807 {
5808 proc_suspended = get_task_pidsuspended((task_t) proc->task);
5809 proc_rele(proc);
5810
5811 if (proc_suspended)
5812 {
5813 logClientIDForNotification(object, context, "PMTellAppWithResponse - Suspended");
5814 return;
5815 }
5816 }
5817 }
5818 }
5819
6d2010ae
A
5820 if (context->messageFilter &&
5821 !context->messageFilter(context->us, object, context, 0, 0))
55e303ae 5822 {
6d2010ae
A
5823 if (kIOLogDebugPower & gIOKitDebug)
5824 {
316670eb 5825 logClientIDForNotification(object, context, "DROP App");
6d2010ae 5826 }
b0d623f7
A
5827 return;
5828 }
2d21ac55 5829
6d2010ae
A
5830 // Create client array (for tracking purposes) only if the service
5831 // has app clients. Usually only root domain does.
b0d623f7 5832 if (0 == context->notifyClients)
b0d623f7 5833 context->notifyClients = OSArray::withCapacity( 32 );
6d2010ae
A
5834
5835 msgType = context->messageType;
5836 msgIndex = context->responseArray->getCount();
5837 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5838
5839 OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
5840 if (kIOLogDebugPower & gIOKitDebug)
5841 {
316670eb 5842 logClientIDForNotification(object, context, "MESG App");
b0d623f7
A
5843 }
5844
6d2010ae
A
5845#if LOG_APP_RESPONSE_TIMES
5846 OSNumber * num;
5847 clock_get_uptime(&now);
5848 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
5849 if (num)
b0d623f7 5850 {
6d2010ae
A
5851 context->responseArray->setObject(msgIndex, num);
5852 num->release();
b0d623f7
A
5853 }
5854 else
6d2010ae
A
5855#endif
5856 context->responseArray->setObject(msgIndex, kOSBooleanFalse);
5857
5858 if (context->notifyClients)
5859 context->notifyClients->setObject(msgIndex, object);
5860
39236c6e 5861 context->us->messageClient(msgType, object, (void *)(uintptr_t) msgRef);
6d2010ae
A
5862}
5863
5864//*********************************************************************************
5865// [static private] pmTellClientWithResponse
5866//
5867// We send a message to an in-kernel client, and we expect a response,
5868// so we compute a cookie we can identify the response with.
5869//*********************************************************************************
5870
39236c6e 5871void IOService::pmTellClientWithResponse( OSObject * object, void * arg )
6d2010ae
A
5872{
5873 IOPowerStateChangeNotification notify;
5874 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5875 OSObject * replied = kOSBooleanTrue;
5876 _IOServiceInterestNotifier * notifier;
5877 uint32_t msgIndex, msgRef, msgType;
5878 IOReturn retCode;
5879
5880 if (context->messageFilter &&
5881 !context->messageFilter(context->us, object, context, 0, 0))
b0d623f7 5882 {
6d2010ae
A
5883 if ((kIOLogDebugPower & gIOKitDebug) &&
5884 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5885 {
5886 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5887 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5888 context->us->getName(),
5889 getIOMessageString(context->messageType),
39236c6e 5890 OBFUSCATE(object), OBFUSCATE(n->handler));
6d2010ae
A
5891 }
5892 return;
5893 }
b0d623f7 5894
6d2010ae
A
5895 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
5896 msgType = context->messageType;
5897 msgIndex = context->responseArray->getCount();
5898 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5899
5900 IOServicePM * pwrMgt = context->us->pwrMgt;
5901 if (gIOKitDebug & kIOLogPower) {
5902 OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
5903 if (OSDynamicCast(IOService, object)) {
5904 const char *who = ((IOService *) object)->getName();
5905 gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
5906 }
5907 else if (notifier) {
5908 OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
5909 }
5910 }
5911 if ((kIOLogDebugPower & gIOKitDebug) && notifier)
5912 {
5913 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5914 context->us->getName(),
5915 getIOMessageString(msgType),
39236c6e 5916 OBFUSCATE(object), OBFUSCATE(notifier->handler));
6d2010ae
A
5917 }
5918
5919 notify.powerRef = (void *)(uintptr_t) msgRef;
5920 notify.returnValue = 0;
5921 notify.stateNumber = context->stateNumber;
5922 notify.stateFlags = context->stateFlags;
5923
5924 if (context->enableTracing && (notifier != 0))
5925 {
5926 uint32_t detail = ((msgIndex & 0xff) << 24) |
5927 ((msgType & 0xfff) << 12) |
5928 (((uintptr_t) notifier->handler) & 0xfff);
5929 getPMRootDomain()->traceDetail( detail );
5930 }
5931
7ddcb079 5932 retCode = context->us->messageClient(msgType, object, (void *) &notify, sizeof(notify));
316670eb
A
5933
5934 if (kIOReturnSuccess == retCode)
6d2010ae 5935 {
316670eb 5936 if (0 == notify.returnValue) {
6d2010ae 5937 OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
316670eb 5938 } else {
6d2010ae
A
5939 replied = kOSBooleanFalse;
5940 if ( notify.returnValue > context->maxTimeRequested )
5941 {
5942 if (notify.returnValue > kPriorityClientMaxWait)
5943 {
5944 context->maxTimeRequested = kPriorityClientMaxWait;
5945 PM_ERROR("%s: client %p returned %llu for %s\n",
5946 context->us->getName(),
39236c6e 5947 notifier ? (void *) OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6d2010ae
A
5948 (uint64_t) notify.returnValue,
5949 getIOMessageString(msgType));
5950 }
5951 else
5952 context->maxTimeRequested = notify.returnValue;
5953 }
b0d623f7 5954 }
316670eb 5955 } else {
6d2010ae
A
5956 // not a client of ours
5957 // so we won't be waiting for response
5958 OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
5959 }
5960
5961 context->responseArray->setObject(msgIndex, replied);
5962}
5963
5964//*********************************************************************************
5965// [static private] pmTellCapabilityAppWithResponse
5966//*********************************************************************************
2d21ac55 5967
39236c6e 5968void IOService::pmTellCapabilityAppWithResponse( OSObject * object, void * arg )
6d2010ae
A
5969{
5970 IOPMSystemCapabilityChangeParameters msgArg;
5971 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5972 OSObject * replied = kOSBooleanTrue;
5973 IOServicePM * pwrMgt = context->us->pwrMgt;
5974 uint32_t msgIndex, msgRef, msgType;
5975#if LOG_APP_RESPONSE_TIMES
5976 AbsoluteTime now;
5977#endif
5978
5979 if (!OSDynamicCast(_IOServiceInterestNotifier, object))
5980 return;
5981
5982 memset(&msgArg, 0, sizeof(msgArg));
5983 if (context->messageFilter &&
5984 !context->messageFilter(context->us, object, context, &msgArg, &replied))
5985 {
5986 return;
5987 }
5988
5989 // Create client array (for tracking purposes) only if the service
5990 // has app clients. Usually only root domain does.
5991 if (0 == context->notifyClients)
5992 context->notifyClients = OSArray::withCapacity( 32 );
5993
5994 msgType = context->messageType;
5995 msgIndex = context->responseArray->getCount();
5996 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5997
5998 OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
5999 if (kIOLogDebugPower & gIOKitDebug)
6000 {
6001 // Log client pid/name and client array index.
316670eb
A
6002 OSNumber * clientID = NULL;
6003 OSString * clientIDString = NULL;;
6d2010ae 6004 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
316670eb
A
6005 if (clientID) {
6006 clientIDString = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6007 }
6008
6d2010ae
A
6009 PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
6010 context->us->getName(),
6011 msgIndex, getIOMessageString(msgType),
6012 (replied != kOSBooleanTrue),
316670eb 6013 clientIDString ? clientIDString->getCStringNoCopy() : "");
6d2010ae 6014 if (clientID) clientID->release();
316670eb 6015 if (clientIDString) clientIDString->release();
6d2010ae
A
6016 }
6017
6018 msgArg.notifyRef = msgRef;
6019 msgArg.maxWaitForReply = 0;
6020
6021 if (replied == kOSBooleanTrue)
6022 {
6023 msgArg.notifyRef = 0;
6024 context->responseArray->setObject(msgIndex, kOSBooleanTrue);
6025 if (context->notifyClients)
6026 context->notifyClients->setObject(msgIndex, kOSBooleanTrue);
6027 }
6028 else
6029 {
2d21ac55
A
6030#if LOG_APP_RESPONSE_TIMES
6031 OSNumber * num;
6032 clock_get_uptime(&now);
6033 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
6034 if (num)
6035 {
6d2010ae 6036 context->responseArray->setObject(msgIndex, num);
2d21ac55
A
6037 num->release();
6038 }
6039 else
6040#endif
6d2010ae 6041 context->responseArray->setObject(msgIndex, kOSBooleanFalse);
2d21ac55 6042
6d2010ae
A
6043 if (context->notifyClients)
6044 context->notifyClients->setObject(msgIndex, object);
1c79356b 6045 }
b0d623f7 6046
6d2010ae 6047 context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
1c79356b
A
6048}
6049
1c79356b 6050//*********************************************************************************
6d2010ae 6051// [static private] pmTellCapabilityClientWithResponse
1c79356b 6052//*********************************************************************************
2d21ac55 6053
6d2010ae
A
6054void IOService::pmTellCapabilityClientWithResponse(
6055 OSObject * object, void * arg )
1c79356b 6056{
6d2010ae 6057 IOPMSystemCapabilityChangeParameters msgArg;
b0d623f7 6058 IOPMInterestContext * context = (IOPMInterestContext *) arg;
6d2010ae
A
6059 OSObject * replied = kOSBooleanTrue;
6060 _IOServiceInterestNotifier * notifier;
6061 uint32_t msgIndex, msgRef, msgType;
b0d623f7 6062 IOReturn retCode;
2d21ac55 6063
6d2010ae
A
6064 memset(&msgArg, 0, sizeof(msgArg));
6065 if (context->messageFilter &&
6066 !context->messageFilter(context->us, object, context, &msgArg, 0))
6067 {
6068 if ((kIOLogDebugPower & gIOKitDebug) &&
6069 (OSDynamicCast(_IOServiceInterestNotifier, object)))
6070 {
6071 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
6072 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
6073 context->us->getName(),
6074 getIOMessageString(context->messageType),
39236c6e 6075 OBFUSCATE(object), OBFUSCATE(n->handler));
6d2010ae 6076 }
b0d623f7 6077 return;
6d2010ae 6078 }
0b4e3aa0 6079
6d2010ae
A
6080 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
6081 msgType = context->messageType;
6082 msgIndex = context->responseArray->getCount();
6083 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
b0d623f7
A
6084
6085 IOServicePM * pwrMgt = context->us->pwrMgt;
91447636 6086 if (gIOKitDebug & kIOLogPower) {
6d2010ae 6087 OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
2d21ac55
A
6088 if (OSDynamicCast(IOService, object)) {
6089 const char *who = ((IOService *) object)->getName();
6d2010ae
A
6090 gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
6091 }
6092 else if (notifier) {
6093 OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
2d21ac55 6094 }
91447636 6095 }
6d2010ae
A
6096 if ((kIOLogDebugPower & gIOKitDebug) && notifier)
6097 {
6098 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
6099 context->us->getName(),
6100 getIOMessageString(msgType),
39236c6e 6101 OBFUSCATE(object), OBFUSCATE(notifier->handler));
6d2010ae 6102 }
91447636 6103
6d2010ae
A
6104 msgArg.notifyRef = msgRef;
6105 msgArg.maxWaitForReply = 0;
6106
6107 if (context->enableTracing && (notifier != 0))
6108 {
6109 uint32_t detail = ((msgIndex & 0xff) << 24) |
6110 ((msgType & 0xfff) << 12) |
6111 (((uintptr_t) notifier->handler) & 0xfff);
6112 getPMRootDomain()->traceDetail( detail );
6113 }
6114
6115 retCode = context->us->messageClient(
6116 msgType, object, (void *) &msgArg, sizeof(msgArg));
6117
6118 if ( kIOReturnSuccess == retCode )
55e303ae 6119 {
6d2010ae 6120 if ( 0 == msgArg.maxWaitForReply )
55e303ae
A
6121 {
6122 // client doesn't want time to respond
6d2010ae
A
6123 OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
6124 }
6125 else
6126 {
6127 replied = kOSBooleanFalse;
6128 if ( msgArg.maxWaitForReply > context->maxTimeRequested )
55e303ae 6129 {
6d2010ae 6130 if (msgArg.maxWaitForReply > kCapabilityClientMaxWait)
55e303ae 6131 {
6d2010ae
A
6132 context->maxTimeRequested = kCapabilityClientMaxWait;
6133 PM_ERROR("%s: client %p returned %u for %s\n",
6134 context->us->getName(),
39236c6e 6135 notifier ? (void *) OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6d2010ae
A
6136 msgArg.maxWaitForReply,
6137 getIOMessageString(msgType));
1c79356b 6138 }
6d2010ae
A
6139 else
6140 context->maxTimeRequested = msgArg.maxWaitForReply;
1c79356b 6141 }
1c79356b 6142 }
6d2010ae
A
6143 }
6144 else
6145 {
55e303ae 6146 // not a client of ours
55e303ae 6147 // so we won't be waiting for response
6d2010ae 6148 OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
1c79356b 6149 }
6d2010ae
A
6150
6151 context->responseArray->setObject(msgIndex, replied);
1c79356b
A
6152}
6153
1c79356b 6154//*********************************************************************************
b0d623f7 6155// [public] tellNoChangeDown
1c79356b
A
6156//
6157// Notify registered applications and kernel clients that we are not
6158// dropping power.
6159//
6160// Subclass can override this to send a different message type. Parameter is
6161// the aborted destination state number.
6162//*********************************************************************************
6163
39236c6e 6164void IOService::tellNoChangeDown( unsigned long )
1c79356b 6165{
2d21ac55 6166 return tellClients( kIOMessageDeviceWillNotPowerOff );
1c79356b
A
6167}
6168
1c79356b 6169//*********************************************************************************
b0d623f7 6170// [public] tellChangeUp
1c79356b
A
6171//
6172// Notify registered applications and kernel clients that we are raising power.
6173//
6174// Subclass can override this to send a different message type. Parameter is
6175// the aborted destination state number.
6176//*********************************************************************************
6177
39236c6e 6178void IOService::tellChangeUp( unsigned long )
1c79356b 6179{
2d21ac55 6180 return tellClients( kIOMessageDeviceHasPoweredOn );
1c79356b
A
6181}
6182
1c79356b 6183//*********************************************************************************
b0d623f7 6184// [protected] tellClients
1c79356b
A
6185//
6186// Notify registered applications and kernel clients of something.
6187//*********************************************************************************
6188
39236c6e 6189void IOService::tellClients( int messageType )
b0d623f7
A
6190{
6191 IOPMInterestContext context;
1c79356b 6192
6d2010ae
A
6193 RD_LOG("tellClients( %s )\n", getIOMessageString(messageType));
6194
6195 memset(&context, 0, sizeof(context));
6196 context.messageType = messageType;
6197 context.isPreChange = fIsPreChange;
6198 context.us = this;
6199 context.stateNumber = fHeadNotePowerState;
6200 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6201 context.changeFlags = fHeadNoteChangeFlags;
6202 context.messageFilter = (IS_ROOT_DOMAIN) ?
6203 OSMemberFunctionCast(
6204 IOPMMessageFilter,
6205 this,
6206 &IOPMrootDomain::systemMessageFilter) : 0;
6207
6208 context.notifyType = kNotifyPriority;
b0d623f7
A
6209 applyToInterested( gIOPriorityPowerStateInterest,
6210 tellKernelClientApplier, (void *) &context );
6d2010ae
A
6211
6212 context.notifyType = kNotifyApps;
b0d623f7
A
6213 applyToInterested( gIOAppPowerStateInterest,
6214 tellAppClientApplier, (void *) &context );
6215
6216 applyToInterested( gIOGeneralInterest,
6217 tellKernelClientApplier, (void *) &context );
1c79356b
A
6218}
6219
1c79356b 6220//*********************************************************************************
b0d623f7 6221// [private] tellKernelClientApplier
1c79356b 6222//
b0d623f7 6223// Message a kernel client.
1c79356b 6224//*********************************************************************************
2d21ac55 6225
39236c6e 6226static void tellKernelClientApplier( OSObject * object, void * arg )
1c79356b 6227{
2d21ac55 6228 IOPowerStateChangeNotification notify;
6d2010ae 6229 IOPMInterestContext * context = (IOPMInterestContext *) arg;
1c79356b 6230
6d2010ae
A
6231 if (context->messageFilter &&
6232 !context->messageFilter(context->us, object, context, 0, 0))
6233 {
6234 if ((kIOLogDebugPower & gIOKitDebug) &&
6235 (OSDynamicCast(_IOServiceInterestNotifier, object)))
6236 {
6237 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
6238 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
6239 context->us->getName(),
6240 IOService::getIOMessageString(context->messageType),
39236c6e 6241 OBFUSCATE(object), OBFUSCATE(n->handler));
6d2010ae 6242 }
b0d623f7 6243 return;
6d2010ae 6244 }
b0d623f7
A
6245
6246 notify.powerRef = (void *) 0;
0b4e3aa0 6247 notify.returnValue = 0;
b0d623f7
A
6248 notify.stateNumber = context->stateNumber;
6249 notify.stateFlags = context->stateFlags;
6250
7ddcb079 6251 context->us->messageClient(context->messageType, object, &notify, sizeof(notify));
6d2010ae
A
6252
6253 if ((kIOLogDebugPower & gIOKitDebug) &&
6254 (OSDynamicCast(_IOServiceInterestNotifier, object)))
6255 {
6256 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
6257 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
6258 context->us->getName(),
6259 IOService::getIOMessageString(context->messageType),
39236c6e 6260 OBFUSCATE(object), OBFUSCATE(n->handler));
6d2010ae 6261 }
b0d623f7
A
6262}
6263
316670eb
A
6264static OSNumber * copyClientIDForNotification(
6265 OSObject *object,
6266 IOPMInterestContext *context)
6267{
6268 OSNumber *clientID = NULL;
6269 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
6270 return clientID;
6271}
6272
6273static void logClientIDForNotification(
6274 OSObject *object,
6275 IOPMInterestContext *context,
6276 const char *logString)
6277{
6278 OSString *logClientID = NULL;
6279 OSNumber *clientID = copyClientIDForNotification(object, context);
6280
6281 if (logString)
6282 {
6283 if (clientID)
6284 logClientID = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6285
6286 PM_LOG("%s %s %s, %s\n",
6287 context->us->getName(), logString,
6288 IOService::getIOMessageString(context->messageType),
6289 logClientID ? logClientID->getCStringNoCopy() : "");
6290
6291 if (logClientID)
6292 logClientID->release();
6293 }
6294
6295 if (clientID)
6296 clientID->release();
6297
6298 return;
6299}
6300
39236c6e 6301static void tellAppClientApplier( OSObject * object, void * arg )
b0d623f7 6302{
6d2010ae 6303 IOPMInterestContext * context = (IOPMInterestContext *) arg;
316670eb
A
6304 OSNumber * clientID = NULL;
6305 proc_t proc = NULL;
6306 boolean_t proc_suspended = FALSE;
6307
6308 if (context->us == IOService::getPMRootDomain())
6309 {
6310 if ((clientID = copyClientIDForNotification(object, context)))
6311 {
6312 uint32_t clientPID = clientID->unsigned32BitValue();
6313 clientID->release();
6314 proc = proc_find(clientPID);
6315
6316 if (proc)
6317 {
6318 proc_suspended = get_task_pidsuspended((task_t) proc->task);
6319 proc_rele(proc);
6320
6321 if (proc_suspended)
6322 {
6323 logClientIDForNotification(object, context, "tellAppClientApplier - Suspended");
6324 return;
6325 }
6326 }
6327 }
6328 }
b0d623f7 6329
6d2010ae
A
6330 if (context->messageFilter &&
6331 !context->messageFilter(context->us, object, context, 0, 0))
6332 {
6333 if (kIOLogDebugPower & gIOKitDebug)
6334 {
316670eb 6335 logClientIDForNotification(object, context, "DROP App");
6d2010ae 6336 }
b0d623f7 6337 return;
6d2010ae
A
6338 }
6339
6340 if (kIOLogDebugPower & gIOKitDebug)
6341 {
316670eb 6342 logClientIDForNotification(object, context, "MESG App");
6d2010ae 6343 }
0b4e3aa0 6344
6d2010ae 6345 context->us->messageClient(context->messageType, object, 0);
1c79356b
A
6346}
6347
2d21ac55
A
6348//*********************************************************************************
6349// [private] checkForDone
6350//*********************************************************************************
1c79356b 6351
39236c6e 6352bool IOService::checkForDone( void )
1c79356b 6353{
2d21ac55
A
6354 int i = 0;
6355 OSObject * theFlag;
1c79356b 6356
316670eb 6357 if (fResponseArray == NULL) {
1c79356b
A
6358 return true;
6359 }
55e303ae 6360
316670eb 6361 for (i = 0; ; i++) {
2d21ac55 6362 theFlag = fResponseArray->getObject(i);
316670eb
A
6363
6364 if (NULL == theFlag) {
1c79356b
A
6365 break;
6366 }
316670eb
A
6367
6368 if (kOSBooleanTrue != theFlag) {
1c79356b
A
6369 return false;
6370 }
6371 }
1c79356b
A
6372 return true;
6373}
6374
2d21ac55
A
6375//*********************************************************************************
6376// [public] responseValid
6377//*********************************************************************************
1c79356b 6378
39236c6e 6379bool IOService::responseValid( uint32_t refcon, int pid )
2d21ac55
A
6380{
6381 UInt16 serialComponent;
6382 UInt16 ordinalComponent;
6383 OSObject * theFlag;
2d21ac55
A
6384
6385 serialComponent = (refcon >> 16) & 0xFFFF;
6386 ordinalComponent = (refcon & 0xFFFF);
6387
6388 if ( serialComponent != fSerialNumber )
55e303ae 6389 {
1c79356b
A
6390 return false;
6391 }
6392
2d21ac55 6393 if ( fResponseArray == NULL )
55e303ae 6394 {
1c79356b
A
6395 return false;
6396 }
6397
2d21ac55 6398 theFlag = fResponseArray->getObject(ordinalComponent);
1c79356b 6399
2d21ac55 6400 if ( theFlag == 0 )
55e303ae 6401 {
1c79356b
A
6402 return false;
6403 }
2d21ac55
A
6404
6405 OSNumber * num;
6406 if ((num = OSDynamicCast(OSNumber, theFlag)))
6407 {
6408#if LOG_APP_RESPONSE_TIMES
6409 AbsoluteTime now;
6410 AbsoluteTime start;
6d2010ae 6411 uint64_t nsec;
39236c6e 6412 char name[128];
2d21ac55 6413
39236c6e
A
6414 name[0] = '\0';
6415 proc_name(pid, name, sizeof(name));
2d21ac55
A
6416 clock_get_uptime(&now);
6417 AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
6418 SUB_ABSOLUTETIME(&now, &start);
6419 absolutetime_to_nanoseconds(now, &nsec);
6d2010ae
A
6420
6421 PMEventDetails *details = PMEventDetails::eventDetails(
6422 kIOPMEventTypeAppResponse, // type
39236c6e 6423 name, // who
6d2010ae
A
6424 (uintptr_t)pid, // owner unique
6425 NULL, // interest name
6426 0, // old
6427 0, // new
6428 0, // result
6429 NS_TO_US(nsec)); // usec completion time
6430
39236c6e 6431 getPMRootDomain()->recordAndReleasePMEvent( details );
6d2010ae
A
6432
6433 if (kIOLogDebugPower & gIOKitDebug)
6434 {
6435 PM_LOG("Ack(%u) %u ms\n",
6436 (uint32_t) ordinalComponent,
6437 NS_TO_MS(nsec));
6438 }
2d21ac55
A
6439
6440 // > 100 ms
6441 if (nsec > LOG_APP_RESPONSE_TIMES)
6442 {
39236c6e
A
6443 PM_LOG("PM response took %d ms (%d, %s)\n", NS_TO_MS(nsec),
6444 pid, name);
b0d623f7
A
6445
6446 if (nsec > LOG_APP_RESPONSE_MSG_TRACER)
6447 {
6448 // TODO: populate the messageType argument
6449 getPMRootDomain()->pmStatsRecordApplicationResponse(
6450 gIOPMStatsApplicationResponseSlow,
39236c6e 6451 name, 0, NS_TO_MS(nsec), pid);
6d2010ae 6452 }
2d21ac55 6453 }
6d2010ae 6454
2d21ac55
A
6455#endif
6456 theFlag = kOSBooleanFalse;
6457 }
6458
6459 if ( kOSBooleanFalse == theFlag )
55e303ae 6460 {
2d21ac55 6461 fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
1c79356b
A
6462 }
6463
1c79356b
A
6464 return true;
6465}
6466
2d21ac55 6467//*********************************************************************************
b0d623f7 6468// [public] allowPowerChange
1c79356b
A
6469//
6470// Our power state is about to lower, and we have notified applications
6471// and kernel clients, and one of them has acknowledged. If this is the last to do
6472// so, and all acknowledgements are positive, we continue with the power change.
2d21ac55
A
6473//*********************************************************************************
6474
39236c6e 6475IOReturn IOService::allowPowerChange( unsigned long refcon )
1c79356b 6476{
2d21ac55
A
6477 IOPMRequest * request;
6478
6479 if ( !initialized )
55e303ae
A
6480 {
6481 // we're unloading
6482 return kIOReturnSuccess;
1c79356b
A
6483 }
6484
2d21ac55
A
6485 request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
6486 if (!request)
2d21ac55 6487 return kIOReturnNoMemory;
2d21ac55 6488
39236c6e
A
6489 request->fArg0 = (void *) refcon;
6490 request->fArg1 = (void *)(uintptr_t) proc_selfpid();
6491 request->fArg2 = (void *) 0;
2d21ac55
A
6492 submitPMRequest( request );
6493
6494 return kIOReturnSuccess;
1c79356b 6495}
2d21ac55 6496
b0d623f7 6497#ifndef __LP64__
39236c6e 6498IOReturn IOService::serializedAllowPowerChange2( unsigned long refcon )
1c79356b 6499{
2d21ac55
A
6500 // [deprecated] public
6501 return kIOReturnUnsupported;
1c79356b 6502}
b0d623f7 6503#endif /* !__LP64__ */
1c79356b 6504
2d21ac55 6505//*********************************************************************************
b0d623f7 6506// [public] cancelPowerChange
1c79356b
A
6507//
6508// Our power state is about to lower, and we have notified applications
6509// and kernel clients, and one of them has vetoed the change. If this is the last
6510// client to respond, we abandon the power change.
2d21ac55
A
6511//*********************************************************************************
6512
39236c6e 6513IOReturn IOService::cancelPowerChange( unsigned long refcon )
1c79356b 6514{
b0d623f7 6515 IOPMRequest * request;
39236c6e
A
6516 char name[128];
6517 pid_t pid = proc_selfpid();
2d21ac55
A
6518
6519 if ( !initialized )
55e303ae
A
6520 {
6521 // we're unloading
6522 return kIOReturnSuccess;
1c79356b
A
6523 }
6524
39236c6e
A
6525 name[0] = '\0';
6526 proc_name(pid, name, sizeof(name));
6527 PM_ERROR("PM notification cancel (pid %d, %s)\n", pid, name);
593a1d5f 6528
2d21ac55
A
6529 request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
6530 if (!request)
b0d623f7 6531 {
b0d623f7
A
6532 return kIOReturnNoMemory;
6533 }
2d21ac55 6534
39236c6e
A
6535 request->fArg0 = (void *) refcon;
6536 request->fArg1 = (void *)(uintptr_t) proc_selfpid();
6537 request->fArg2 = (void *) OSString::withCString(name);
b0d623f7 6538 submitPMRequest( request );
2d21ac55 6539
b0d623f7 6540 return kIOReturnSuccess;
1c79356b
A
6541}
6542
b0d623f7 6543#ifndef __LP64__
39236c6e 6544IOReturn IOService::serializedCancelPowerChange2( unsigned long refcon )
1c79356b 6545{
2d21ac55
A
6546 // [deprecated] public
6547 return kIOReturnUnsupported;
1c79356b
A
6548}
6549
1c79356b
A
6550//*********************************************************************************
6551// PM_Clamp_Timer_Expired
6552//
6553// called when clamp timer expires...set power state to 0.
6554//*********************************************************************************
6555
39236c6e 6556void IOService::PM_Clamp_Timer_Expired( void )
1c79356b 6557{
1c79356b
A
6558}
6559
2d21ac55 6560//*********************************************************************************
91447636 6561// clampPowerOn
1c79356b 6562//
91447636 6563// Set to highest available power state for a minimum of duration milliseconds
2d21ac55 6564//*********************************************************************************
91447636 6565
39236c6e 6566void IOService::clampPowerOn( unsigned long duration )
1c79356b 6567{
91447636 6568}
b0d623f7 6569#endif /* !__LP64__ */
1c79356b 6570
39236c6e
A
6571//*********************************************************************************
6572// configurePowerStateReport
6573//
6574// Configures the IOStateReport for kPMPowerStateChannel
6575//*********************************************************************************
6576IOReturn IOService::configurePowerStatesReport( IOReportConfigureAction action, void *result )
6577{
6578
6579 IOReturn rc = kIOReturnSuccess;
6580 size_t reportSize;
6581 unsigned long i;
6582 uint64_t ts;
6583
6584 if (!pwrMgt)
6585 return kIOReturnUnsupported;
6586
6587 if (!fNumberOfPowerStates)
6588 return kIOReturnSuccess; // For drivers which are in power plane, but haven't called registerPowerDriver()
6589 PM_LOCK();
6590
6591 switch (action)
6592 {
6593 case kIOReportEnable:
6594 if (fReportBuf)
6595 {
6596 fReportClientCnt++;
6597 break;
6598 }
6599 reportSize = STATEREPORT_BUFSIZE(fNumberOfPowerStates);
6600 fReportBuf = IOMalloc(reportSize);
6601 if (!fReportBuf) {
6602 rc = kIOReturnNoMemory;
6603 break;
6604 }
6605 memset(fReportBuf, 0, reportSize);
6606
6607 STATEREPORT_INIT(fNumberOfPowerStates, fReportBuf, reportSize,
6608 getRegistryEntryID(), kPMPowerStatesChID, kIOReportCategoryPower);
6609
6610 for (i = 0; i < fNumberOfPowerStates; i++) {
6611 unsigned bits = 0;
6612
6613 if (fPowerStates[i].capabilityFlags & kIOPMPowerOn)
6614 bits |= kPMReportPowerOn;
6615 if (fPowerStates[i].capabilityFlags & kIOPMDeviceUsable)
6616 bits |= kPMReportDeviceUsable;
6617 if (fPowerStates[i].capabilityFlags & kIOPMLowPower)
6618 bits |= kPMReportLowPower;
6619
6620 STATEREPORT_SETSTATEID(fReportBuf, i, ((bits & 0xff) << 8) |
6621 ((StateOrder(fMaxPowerState) & 0xf) << 4) | (StateOrder(i) & 0xf));
6622 }
6623 ts = mach_absolute_time();
6624 STATEREPORT_SETSTATE(fReportBuf, fCurrentPowerState, ts);
6625 break;
6626
6627 case kIOReportDisable:
6628 if (fReportClientCnt == 0) {
6629 rc = kIOReturnBadArgument;
6630 break;
6631 }
6632 if (fReportClientCnt == 1)
6633 {
6634 IOFree(fReportBuf, STATEREPORT_BUFSIZE(fNumberOfPowerStates));
6635 fReportBuf = NULL;
6636 }
6637 fReportClientCnt--;
6638 break;
6639
6640 case kIOReportGetDimensions:
6641 if (fReportBuf)
6642 STATEREPORT_UPDATERES(fReportBuf, kIOReportGetDimensions, result);
6643 break;
6644 }
6645
6646 PM_UNLOCK();
6647
6648 return rc;
6649}
6650
6651//*********************************************************************************
6652// updatePowerStateReport
6653//
6654// Updates the IOStateReport for kPMPowerStateChannel
6655//*********************************************************************************
6656IOReturn IOService::updatePowerStatesReport( IOReportConfigureAction action, void *result, void *destination )
6657{
6658 uint32_t size2cpy;
6659 void *data2cpy;
6660 uint64_t ts;
6661 IOReturn rc = kIOReturnSuccess;
6662 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
6663
6664
6665 if (!pwrMgt)
6666 return kIOReturnUnsupported;
6667 if (!fNumberOfPowerStates)
6668 return kIOReturnSuccess;
6669
6670 if ( !result || !dest ) return kIOReturnBadArgument;
6671 PM_LOCK();
6672
6673 switch (action) {
6674 case kIOReportCopyChannelData:
6675 if ( !fReportBuf ) {
6676 rc = kIOReturnNotOpen;
6677 break;
6678 }
6679
6680 ts = mach_absolute_time();
6681 STATEREPORT_UPDATEPREP(fReportBuf, ts, data2cpy, size2cpy);
6682 if (size2cpy > (dest->getCapacity() - dest->getLength()) ) {
6683 rc = kIOReturnOverrun;
6684 break;
6685 }
6686
6687 STATEREPORT_UPDATERES(fReportBuf, kIOReportCopyChannelData, result);
6688 dest->appendBytes(data2cpy, size2cpy);
6689
6690 default:
6691 break;
6692
6693 }
6694
6695 PM_UNLOCK();
6696
6697 return rc;
6698
6699}
6700
6701//*********************************************************************************
6702// configureSimplePowerReport
6703//
6704// Configures the IOSimpleReport for given channel id
6705//*********************************************************************************
6706IOReturn IOService::configureSimplePowerReport(IOReportConfigureAction action, void *result )
6707{
6708
6709 IOReturn rc = kIOReturnSuccess;
6710
6711 if ( !pwrMgt )
6712 return kIOReturnUnsupported;
6713
6714 if ( !fNumberOfPowerStates )
6715 return rc;
6716
6717 switch (action)
6718 {
6719 case kIOReportEnable:
6720 case kIOReportDisable:
6721 break;
6722
6723 case kIOReportGetDimensions:
6724 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
6725 break;
6726 }
6727
6728
6729 return rc;
6730}
6731
6732//*********************************************************************************
6733// updateSimplePowerReport
6734//
6735// Updates the IOSimpleReport for the given chanel id
6736//*********************************************************************************
6737IOReturn IOService::updateSimplePowerReport( IOReportConfigureAction action, void *result, void *destination )
6738{
6739 uint32_t size2cpy;
6740 void *data2cpy;
6741 uint64_t buf[SIMPLEREPORT_BUFSIZE/sizeof(uint64_t)+1]; // Force a 8-byte alignment
6742 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
6743 IOReturn rc = kIOReturnSuccess;
6744 unsigned bits = 0;
6745
6746
6747 if ( !pwrMgt )
6748 return kIOReturnUnsupported;
6749 if ( !result || !dest ) return kIOReturnBadArgument;
6750
6751 if ( !fNumberOfPowerStates )
6752 return rc;
6753 PM_LOCK();
6754
6755 switch (action) {
6756 case kIOReportCopyChannelData:
6757
6758 SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), kPMCurrStateChID, kIOReportCategoryPower);
6759
6760 if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMPowerOn)
6761 bits |= kPMReportPowerOn;
6762 if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMDeviceUsable)
6763 bits |= kPMReportDeviceUsable;
6764 if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMLowPower)
6765 bits |= kPMReportLowPower;
6766
6767
6768 SIMPLEREPORT_SETVALUE(buf, ((bits & 0xff) << 8) | ((StateOrder(fMaxPowerState) & 0xf) << 4) |
6769 (StateOrder(fCurrentPowerState) & 0xf));
6770
6771 SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
6772 if (size2cpy > (dest->getCapacity() - dest->getLength())) {
6773 rc = kIOReturnOverrun;
6774 break;
6775 }
6776
6777 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
6778 dest->appendBytes(data2cpy, size2cpy);
6779
6780 default:
6781 break;
6782
6783 }
6784
6785 PM_UNLOCK();
6786
6787 return kIOReturnSuccess;
6788
6789}
6790
6791
6792
6d2010ae
A
6793// MARK: -
6794// MARK: Driver Overrides
6795
1c79356b 6796//*********************************************************************************
b0d623f7 6797// [public] setPowerState
1c79356b
A
6798//
6799// Does nothing here. This should be implemented in a subclass driver.
6800//*********************************************************************************
6801
39236c6e 6802IOReturn IOService::setPowerState(
2d21ac55 6803 unsigned long powerStateOrdinal, IOService * whatDevice )
1c79356b
A
6804{
6805 return IOPMNoErr;
6806}
6807
1c79356b 6808//*********************************************************************************
b0d623f7 6809// [public] maxCapabilityForDomainState
1c79356b 6810//
39236c6e
A
6811// Finds the highest power state in the array whose input power requirement
6812// is equal to the input parameter. Where a more intelligent decision is
6813// possible, override this in the subclassed driver.
1c79356b
A
6814//*********************************************************************************
6815
39236c6e 6816IOPMPowerStateIndex IOService::getPowerStateForDomainFlags( IOPMPowerFlags flags )
1c79356b 6817{
39236c6e
A
6818 IOPMPowerStateIndex stateIndex;
6819
6820 if (!fNumberOfPowerStates)
6821 return kPowerStateZero;
6822
6823 for ( int order = fNumberOfPowerStates - 1; order >= 0; order-- )
6824 {
6825 stateIndex = fPowerStates[order].stateOrderToIndex;
6826
6827 if ( (flags & fPowerStates[stateIndex].inputPowerFlags) ==
6828 fPowerStates[stateIndex].inputPowerFlags )
6829 {
6830 return stateIndex;
6831 }
6832 }
6833 return kPowerStateZero;
6834}
1c79356b 6835
39236c6e
A
6836unsigned long IOService::maxCapabilityForDomainState( IOPMPowerFlags domainState )
6837{
6838 return getPowerStateForDomainFlags(domainState);
1c79356b
A
6839}
6840
1c79356b 6841//*********************************************************************************
b0d623f7 6842// [public] initialPowerStateForDomainState
1c79356b 6843//
39236c6e 6844// Called to query the power state for the initial power transition.
1c79356b
A
6845//*********************************************************************************
6846
39236c6e 6847unsigned long IOService::initialPowerStateForDomainState( IOPMPowerFlags domainState )
1c79356b 6848{
bd504ef0
A
6849 if (fResetPowerStateOnWake && (domainState & kIOPMRootDomainState))
6850 {
6851 // Return lowest power state for any root power domain changes
39236c6e 6852 return kPowerStateZero;
bd504ef0
A
6853 }
6854
39236c6e 6855 return getPowerStateForDomainFlags(domainState);
1c79356b
A
6856}
6857
1c79356b 6858//*********************************************************************************
b0d623f7 6859// [public] powerStateForDomainState
1c79356b 6860//
39236c6e 6861// This method is not called from PM.
1c79356b
A
6862//*********************************************************************************
6863
39236c6e 6864unsigned long IOService::powerStateForDomainState( IOPMPowerFlags domainState )
1c79356b 6865{
39236c6e 6866 return getPowerStateForDomainFlags(domainState);
1c79356b
A
6867}
6868
b0d623f7 6869#ifndef __LP64__
1c79356b 6870//*********************************************************************************
b0d623f7 6871// [deprecated] didYouWakeSystem
1c79356b
A
6872//
6873// Does nothing here. This should be implemented in a subclass driver.
6874//*********************************************************************************
6875
39236c6e 6876bool IOService::didYouWakeSystem( void )
1c79356b
A
6877{
6878 return false;
6879}
b0d623f7 6880#endif /* !__LP64__ */
1c79356b 6881
1c79356b 6882//*********************************************************************************
b0d623f7 6883// [public] powerStateWillChangeTo
1c79356b
A
6884//
6885// Does nothing here. This should be implemented in a subclass driver.
6886//*********************************************************************************
6887
39236c6e 6888IOReturn IOService::powerStateWillChangeTo( IOPMPowerFlags, unsigned long, IOService * )
1c79356b 6889{
2d21ac55 6890 return kIOPMAckImplied;
1c79356b
A
6891}
6892
1c79356b 6893//*********************************************************************************
b0d623f7 6894// [public] powerStateDidChangeTo
1c79356b
A
6895//
6896// Does nothing here. This should be implemented in a subclass driver.
6897//*********************************************************************************
6898
39236c6e 6899IOReturn IOService::powerStateDidChangeTo( IOPMPowerFlags, unsigned long, IOService * )
1c79356b 6900{
2d21ac55 6901 return kIOPMAckImplied;
1c79356b
A
6902}
6903
1c79356b 6904//*********************************************************************************
b0d623f7 6905// [protected] powerChangeDone
1c79356b 6906//
2d21ac55 6907// Called from PM work loop thread.
1c79356b
A
6908// Does nothing here. This should be implemented in a subclass policy-maker.
6909//*********************************************************************************
6910
39236c6e 6911void IOService::powerChangeDone( unsigned long )
1c79356b
A
6912{
6913}
6914
b0d623f7 6915#ifndef __LP64__
1c79356b 6916//*********************************************************************************
b0d623f7 6917// [deprecated] newTemperature
1c79356b
A
6918//
6919// Does nothing here. This should be implemented in a subclass driver.
6920//*********************************************************************************
6921
39236c6e 6922IOReturn IOService::newTemperature( long currentTemp, IOService * whichZone )
1c79356b
A
6923{
6924 return IOPMNoErr;
6925}
b0d623f7 6926#endif /* !__LP64__ */
1c79356b 6927
2d21ac55 6928//*********************************************************************************
b0d623f7 6929// [public] systemWillShutdown
2d21ac55
A
6930//
6931// System shutdown and restart notification.
6932//*********************************************************************************
1c79356b 6933
2d21ac55
A
6934void IOService::systemWillShutdown( IOOptionBits specifier )
6935{
6936 IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
6937 if (rootDomain)
6938 rootDomain->acknowledgeSystemWillShutdown( this );
6939}
1c79356b 6940
6d2010ae
A
6941// MARK: -
6942// MARK: PM State Machine
6943
1c79356b 6944//*********************************************************************************
2d21ac55
A
6945// [private static] acquirePMRequest
6946//*********************************************************************************
6947
6948IOPMRequest *
b0d623f7
A
6949IOService::acquirePMRequest( IOService * target, IOOptionBits requestType,
6950 IOPMRequest * active )
2d21ac55
A
6951{
6952 IOPMRequest * request;
6953
6954 assert(target);
6955
6956 request = IOPMRequest::create();
6957 if (request)
6958 {
6959 request->init( target, requestType );
b0d623f7
A
6960 if (active)
6961 {
6962 IOPMRequest * root = active->getRootRequest();
6963 if (root) request->attachRootRequest(root);
6964 }
6965 }
6966 else
6967 {
6968 PM_ERROR("%s: No memory for PM request type 0x%x\n",
6969 target->getName(), (uint32_t) requestType);
2d21ac55
A
6970 }
6971 return request;
6972}
6973
6974//*********************************************************************************
6975// [private static] releasePMRequest
6976//*********************************************************************************
6977
6978void IOService::releasePMRequest( IOPMRequest * request )
6979{
6980 if (request)
6981 {
6982 request->reset();
6983 request->release();
6984 }
6985}
6986
6987//*********************************************************************************
6988// [private] submitPMRequest
6989//*********************************************************************************
6990
6991void IOService::submitPMRequest( IOPMRequest * request )
6992{
6993 assert( request );
6994 assert( gIOPMReplyQueue );
6995 assert( gIOPMRequestQueue );
6996
6d2010ae 6997 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
39236c6e
A
6998 (long)request->getType(), OBFUSCATE(request),
6999 OBFUSCATE(request->getTarget()), request->getTarget()->getName(),
7000 OBFUSCATE(request->fArg0),
7001 OBFUSCATE(request->fArg1), OBFUSCATE(request->fArg2));
2d21ac55 7002
b0d623f7 7003 if (request->isReplyType())
2d21ac55
A
7004 gIOPMReplyQueue->queuePMRequest( request );
7005 else
7006 gIOPMRequestQueue->queuePMRequest( request );
7007}
7008
7009void IOService::submitPMRequest( IOPMRequest ** requests, IOItemCount count )
7010{
7011 assert( requests );
7012 assert( count > 0 );
7013 assert( gIOPMRequestQueue );
7014
7015 for (IOItemCount i = 0; i < count; i++)
7016 {
7017 IOPMRequest * req = requests[i];
6d2010ae 7018 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
39236c6e
A
7019 (long)req->getType(), OBFUSCATE(req),
7020 OBFUSCATE(req->getTarget()), req->getTarget()->getName(),
7021 OBFUSCATE(req->fArg0),
7022 OBFUSCATE(req->fArg1), OBFUSCATE(req->fArg2));
2d21ac55
A
7023 }
7024
7025 gIOPMRequestQueue->queuePMRequestChain( requests, count );
7026}
7027
7028//*********************************************************************************
7029// [private] servicePMRequestQueue
6d2010ae
A
7030//
7031// Called from IOPMRequestQueue::checkForWork().
2d21ac55
A
7032//*********************************************************************************
7033
7034bool IOService::servicePMRequestQueue(
7035 IOPMRequest * request,
7036 IOPMRequestQueue * queue )
7037{
6d2010ae 7038 bool more;
2d21ac55 7039
6d2010ae
A
7040 if (initialized)
7041 {
7042 // Work queue will immediately execute the queue'd request if possible.
7043 // If execution blocks, the work queue will wait for a producer signal.
7044 // Only need to signal more when completing attached requests.
2d21ac55 7045
6d2010ae
A
7046 more = gIOPMWorkQueue->queuePMRequest(request, pwrMgt);
7047 return more;
7048 }
2d21ac55 7049
6d2010ae 7050 // Calling PM without PMinit() is not allowed, fail the request.
2d21ac55 7051
6d2010ae 7052 PM_LOG("%s: PM not initialized\n", getName());
b0d623f7 7053 fAdjustPowerScheduled = false;
6d2010ae
A
7054 more = gIOPMFreeQueue->queuePMRequest(request);
7055 if (more) gIOPMWorkQueue->incrementProducerCount();
7056 return more;
2d21ac55
A
7057}
7058
7059//*********************************************************************************
7060// [private] servicePMFreeQueue
7061//
6d2010ae 7062// Called from IOPMCompletionQueue::checkForWork().
2d21ac55
A
7063//*********************************************************************************
7064
7065bool IOService::servicePMFreeQueue(
b0d623f7
A
7066 IOPMRequest * request,
7067 IOPMCompletionQueue * queue )
2d21ac55 7068{
b0d623f7
A
7069 bool more = request->getNextRequest();
7070 IOPMRequest * root = request->getRootRequest();
7071
7072 if (root && (root != request))
7073 more = true;
6d2010ae
A
7074 if (more)
7075 gIOPMWorkQueue->incrementProducerCount();
060df5ea 7076
2d21ac55
A
7077 releasePMRequest( request );
7078 return more;
7079}
7080
7081//*********************************************************************************
7082// [private] retirePMRequest
1c79356b 7083//
2d21ac55 7084// Called by IOPMWorkQueue to retire a completed request.
1c79356b 7085//*********************************************************************************
2d21ac55
A
7086
7087bool IOService::retirePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
1c79356b 7088{
2d21ac55 7089 assert(request && queue);
1c79356b 7090
6d2010ae 7091 PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
39236c6e
A
7092 request->getType(), OBFUSCATE(request),
7093 OBFUSCATE(this), getName(),
2d21ac55 7094 fMachineState, gIOPMBusyCount);
91447636 7095
b0d623f7 7096 // Catch requests created by idleTimerExpired().
1c79356b 7097
2d21ac55 7098 if ((request->getType() == kIOPMRequestTypeActivityTickle) &&
bd504ef0
A
7099 (((uintptr_t) request->fArg1) & kTickleTypePowerDrop) &&
7100 fIdleTimerPeriod)
2d21ac55 7101 {
bd504ef0 7102 restartIdleTimer();
db609669 7103 }
1c79356b 7104
6d2010ae
A
7105 // If the request is linked, then Work queue has already incremented its
7106 // producer count.
7107
7108 return (gIOPMFreeQueue->queuePMRequest( request ));
2d21ac55 7109}
1c79356b 7110
2d21ac55
A
7111//*********************************************************************************
7112// [private] isPMBlocked
7113//
7114// Check if machine state transition is blocked.
7115//*********************************************************************************
1c79356b 7116
39236c6e 7117bool IOService::isPMBlocked( IOPMRequest * request, int count )
2d21ac55
A
7118{
7119 int reason = 0;
7120
7121 do {
7122 if (kIOPM_Finished == fMachineState)
7123 break;
7124
7125 if (kIOPM_DriverThreadCallDone == fMachineState)
7126 {
7127 // 5 = kDriverCallInformPreChange
7128 // 6 = kDriverCallInformPostChange
7129 // 7 = kDriverCallSetPowerState
39236c6e 7130 // 8 = kRootDomainInformPreChange
6d2010ae
A
7131 if (fDriverCallBusy)
7132 reason = 5 + fDriverCallReason;
2d21ac55
A
7133 break;
7134 }
7135
7136 // Waiting on driver's setPowerState() timeout.
7137 if (fDriverTimer)
7138 {
7139 reason = 1; break;
7140 }
7141
7142 // Child or interested driver acks pending.
7143 if (fHeadNotePendingAcks)
7144 {
7145 reason = 2; break;
7146 }
7147
7148 // Waiting on apps or priority power interest clients.
7149 if (fResponseArray)
7150 {
7151 reason = 3; break;
7152 }
7153
7154 // Waiting on settle timer expiration.
7155 if (fSettleTimeUS)
7156 {
7157 reason = 4; break;
7158 }
7159 } while (false);
7160
7161 fWaitReason = reason;
7162
7163 if (reason)
7164 {
7165 if (count)
7166 {
6d2010ae 7167 PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
39236c6e
A
7168 request->getType(), OBFUSCATE(request),
7169 OBFUSCATE(this), getName(),
2d21ac55
A
7170 fMachineState, reason);
7171 }
7172
7173 return true;
7174 }
1c79356b 7175
2d21ac55 7176 return false;
1c79356b
A
7177}
7178
2d21ac55
A
7179//*********************************************************************************
7180// [private] servicePMRequest
7181//
7182// Service a request from our work queue.
7183//*********************************************************************************
7184
7185bool IOService::servicePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
7186{
7187 bool done = false;
7188 int loop = 0;
7189
7190 assert(request && queue);
7191
7192 while (isPMBlocked(request, loop++) == false)
7193 {
6d2010ae 7194 PM_LOG1("[W %02x] %p [%p %s] state %d\n",
39236c6e
A
7195 request->getType(), OBFUSCATE(request),
7196 OBFUSCATE(this), getName(), fMachineState);
2d21ac55 7197
b0d623f7 7198 gIOPMRequest = request;
6d2010ae 7199 gIOPMWorkCount++;
2d21ac55
A
7200
7201 // Every PM machine states must be handled in one of the cases below.
7202
7203 switch ( fMachineState )
7204 {
7205 case kIOPM_Finished:
39236c6e
A
7206 start_watchdog_timer();
7207
2d21ac55
A
7208 executePMRequest( request );
7209 break;
7210
7211 case kIOPM_OurChangeTellClientsPowerDown:
6d2010ae
A
7212 // Root domain might self cancel due to assertions.
7213 if (IS_ROOT_DOMAIN)
7214 {
7215 bool cancel = (bool) fDoNotPowerDown;
7216 getPMRootDomain()->askChangeDownDone(
7217 &fHeadNoteChangeFlags, &cancel);
7218 fDoNotPowerDown = cancel;
7219 }
7220
7221 // askChangeDown() done, was it vetoed?
2d21ac55
A
7222 if (!fDoNotPowerDown)
7223 {
6d2010ae
A
7224 if (IS_ROOT_DOMAIN) {
7225 PMEventDetails *details = PMEventDetails::eventDetails(
7226 kIOPMEventTypeAppNotificationsFinished,
7227 NULL,
7228 0,
7229 0);
7230
39236c6e 7231 getPMRootDomain()->recordAndReleasePMEvent( details );
6d2010ae
A
7232 }
7233
2d21ac55
A
7234 // no, we can continue
7235 OurChangeTellClientsPowerDown();
7236 }
7237 else
7238 {
6d2010ae
A
7239 if (IS_ROOT_DOMAIN) {
7240 PMEventDetails *details = PMEventDetails::eventDetails(
7241 kIOPMEventTypeSleepDone,
7242 NULL,
7243 1, /* reason: 1 == Ask clients succeeded */
7244 kIOReturnAborted); /* result */
7245
39236c6e 7246 getPMRootDomain()->recordAndReleasePMEvent( details );
6d2010ae
A
7247 }
7248
593a1d5f 7249 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
39236c6e 7250 PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
2d21ac55 7251 // yes, rescind the warning
b0d623f7 7252 tellNoChangeDown(fHeadNotePowerState);
2d21ac55 7253 // mark the change note un-actioned
6d2010ae 7254 fHeadNoteChangeFlags |= kIOPMNotDone;
2d21ac55 7255 // and we're done
6d2010ae 7256 OurChangeFinish();
2d21ac55
A
7257 }
7258 break;
7259
39236c6e
A
7260 case kIOPM_OurChangeTellUserPMPolicyPowerDown:
7261 // PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
7262 if (fDoNotPowerDown)
7263 {
7264 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7265 PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7266 // yes, rescind the warning
7267 tellNoChangeDown(fHeadNotePowerState);
7268 // mark the change note un-actioned
7269 fHeadNoteChangeFlags |= kIOPMNotDone;
7270 // and we're done
7271 OurChangeFinish();
7272 }
7273 else
7274 OurChangeTellUserPMPolicyPowerDown();
7275 break;
7276
2d21ac55 7277 case kIOPM_OurChangeTellPriorityClientsPowerDown:
39236c6e
A
7278 // PMRD: LastCallBeforeSleep notify done
7279 // Non-PMRD: tellChangeDown/kNotifyApps done
593a1d5f
A
7280 if (fDoNotPowerDown)
7281 {
6d2010ae
A
7282 if (IS_ROOT_DOMAIN) {
7283 PMEventDetails *details = PMEventDetails::eventDetails(
7284 kIOPMEventTypeSleepDone,
7285 NULL,
7286 2, /* reason: 2 == Client cancelled wake */
7287 kIOReturnAborted); /* result */
7288
39236c6e 7289 getPMRootDomain()->recordAndReleasePMEvent( details );
6d2010ae 7290 }
593a1d5f 7291 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
39236c6e 7292 PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
593a1d5f
A
7293 // no, tell clients we're back in the old state
7294 tellChangeUp(fCurrentPowerState);
7295 // mark the change note un-actioned
6d2010ae 7296 fHeadNoteChangeFlags |= kIOPMNotDone;
593a1d5f 7297 // and we're done
6d2010ae 7298 OurChangeFinish();
593a1d5f
A
7299 }
7300 else
593a1d5f 7301 {
6d2010ae
A
7302 if (IS_ROOT_DOMAIN) {
7303 PMEventDetails *details = PMEventDetails::eventDetails(
7304 kIOPMEventTypeAppNotificationsFinished,
7305 NULL,
7306 2, /* reason: 2 == TellPriorityClientsDone */
7307 kIOReturnSuccess); /* result */
7308
39236c6e 7309 getPMRootDomain()->recordAndReleasePMEvent( details );
6d2010ae 7310 }
593a1d5f
A
7311 // yes, we can continue
7312 OurChangeTellPriorityClientsPowerDown();
7313 }
2d21ac55
A
7314 break;
7315
7316 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
7317 OurChangeNotifyInterestedDriversWillChange();
7318 break;
7319
7320 case kIOPM_OurChangeSetPowerState:
7321 OurChangeSetPowerState();
7322 break;
7323
7324 case kIOPM_OurChangeWaitForPowerSettle:
7325 OurChangeWaitForPowerSettle();
7326 break;
7327
7328 case kIOPM_OurChangeNotifyInterestedDriversDidChange:
7329 OurChangeNotifyInterestedDriversDidChange();
7330 break;
7331
6d2010ae
A
7332 case kIOPM_OurChangeTellCapabilityDidChange:
7333 OurChangeTellCapabilityDidChange();
7334 break;
7335
2d21ac55
A
7336 case kIOPM_OurChangeFinish:
7337 OurChangeFinish();
7338 break;
7339
6d2010ae
A
7340 case kIOPM_ParentChangeTellPriorityClientsPowerDown:
7341 ParentChangeTellPriorityClientsPowerDown();
2d21ac55
A
7342 break;
7343
6d2010ae
A
7344 case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
7345 ParentChangeNotifyInterestedDriversWillChange();
2d21ac55
A
7346 break;
7347
6d2010ae
A
7348 case kIOPM_ParentChangeSetPowerState:
7349 ParentChangeSetPowerState();
2d21ac55
A
7350 break;
7351
6d2010ae
A
7352 case kIOPM_ParentChangeWaitForPowerSettle:
7353 ParentChangeWaitForPowerSettle();
2d21ac55
A
7354 break;
7355
6d2010ae
A
7356 case kIOPM_ParentChangeNotifyInterestedDriversDidChange:
7357 ParentChangeNotifyInterestedDriversDidChange();
2d21ac55
A
7358 break;
7359
6d2010ae
A
7360 case kIOPM_ParentChangeTellCapabilityDidChange:
7361 ParentChangeTellCapabilityDidChange();
7362 break;
2d21ac55 7363
6d2010ae
A
7364 case kIOPM_ParentChangeAcknowledgePowerChange:
7365 ParentChangeAcknowledgePowerChange();
2d21ac55
A
7366 break;
7367
2d21ac55 7368 case kIOPM_DriverThreadCallDone:
39236c6e
A
7369 switch (fDriverCallReason)
7370 {
7371 case kDriverCallInformPreChange:
7372 case kDriverCallInformPostChange:
7373 notifyInterestedDriversDone();
7374 break;
7375 case kDriverCallSetPowerState:
7376 notifyControllingDriverDone();
7377 break;
7378 case kRootDomainInformPreChange:
7379 notifyRootDomainDone();
7380 break;
7381 default:
7382 panic("%s: bad call reason %x",
7383 getName(), fDriverCallReason);
7384 }
2d21ac55
A
7385 break;
7386
6d2010ae
A
7387 case kIOPM_NotifyChildrenOrdered:
7388 notifyChildrenOrdered();
7389 break;
7390
7391 case kIOPM_NotifyChildrenDelayed:
7392 notifyChildrenDelayed();
7393 break;
7394
7395 case kIOPM_NotifyChildrenStart:
39236c6e
A
7396 // pop notifyAll() state saved by notifyInterestedDriversDone()
7397 MS_POP();
7398 notifyRootDomain();
6d2010ae
A
7399 break;
7400
7401 case kIOPM_SyncTellClientsPowerDown:
7402 // Root domain might self cancel due to assertions.
7403 if (IS_ROOT_DOMAIN)
7404 {
7405 bool cancel = (bool) fDoNotPowerDown;
7406 getPMRootDomain()->askChangeDownDone(
7407 &fHeadNoteChangeFlags, &cancel);
7408 fDoNotPowerDown = cancel;
39236c6e 7409 }
6d2010ae
A
7410 if (!fDoNotPowerDown)
7411 {
7412 fMachineState = kIOPM_SyncTellPriorityClientsPowerDown;
7413 fOutOfBandParameter = kNotifyApps;
7414 tellChangeDown(fHeadNotePowerState);
7415 }
7416 else
7417 {
39236c6e
A
7418 // Cancelled by IOPMrootDomain::askChangeDownDone() or
7419 // askChangeDown/kNotifyApps
6d2010ae 7420 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
39236c6e 7421 PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
6d2010ae
A
7422 tellNoChangeDown(fHeadNotePowerState);
7423 fHeadNoteChangeFlags |= kIOPMNotDone;
7424 OurChangeFinish();
7425 }
7426 break;
7427
7428 case kIOPM_SyncTellPriorityClientsPowerDown:
39236c6e 7429 // PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
6d2010ae
A
7430 if (!fDoNotPowerDown)
7431 {
7432 fMachineState = kIOPM_SyncNotifyWillChange;
7433 fOutOfBandParameter = kNotifyPriority;
7434 tellChangeDown(fHeadNotePowerState);
7435 }
7436 else
7437 {
7438 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
39236c6e 7439 PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
6d2010ae
A
7440 tellChangeUp(fCurrentPowerState);
7441 fHeadNoteChangeFlags |= kIOPMNotDone;
7442 OurChangeFinish();
7443 }
2d21ac55
A
7444 break;
7445
6d2010ae
A
7446 case kIOPM_SyncNotifyWillChange:
7447 if (kIOPMSyncNoChildNotify & fHeadNoteChangeFlags)
7448 {
7449 fMachineState = kIOPM_SyncFinish;
7450 continue;
7451 }
7452 fMachineState = kIOPM_SyncNotifyDidChange;
7453 fDriverCallReason = kDriverCallInformPreChange;
7454 notifyChildren();
7455 break;
7456
b0d623f7 7457 case kIOPM_SyncNotifyDidChange:
6d2010ae
A
7458 fIsPreChange = false;
7459
7460 if (fHeadNoteChangeFlags & kIOPMParentInitiated)
bd504ef0 7461 {
6d2010ae 7462 fMachineState = kIOPM_SyncFinish;
bd504ef0 7463 }
6d2010ae 7464 else
bd504ef0
A
7465 {
7466 assert(IS_ROOT_DOMAIN);
6d2010ae 7467 fMachineState = kIOPM_SyncTellCapabilityDidChange;
bd504ef0 7468 }
6d2010ae 7469
b0d623f7
A
7470 fDriverCallReason = kDriverCallInformPostChange;
7471 notifyChildren();
7472 break;
7473
6d2010ae
A
7474 case kIOPM_SyncTellCapabilityDidChange:
7475 tellSystemCapabilityChange( kIOPM_SyncFinish );
7476 break;
7477
b0d623f7 7478 case kIOPM_SyncFinish:
6d2010ae
A
7479 if (fHeadNoteChangeFlags & kIOPMParentInitiated)
7480 ParentChangeAcknowledgePowerChange();
b0d623f7
A
7481 else
7482 OurChangeFinish();
6d2010ae
A
7483 break;
7484
7485 case kIOPM_TellCapabilityChangeDone:
7486 if (fIsPreChange)
7487 {
7488 if (fOutOfBandParameter == kNotifyCapabilityChangePriority)
7489 {
7490 MS_POP(); // tellSystemCapabilityChange()
7491 continue;
7492 }
7493 fOutOfBandParameter = kNotifyCapabilityChangePriority;
7494 }
7495 else
7496 {
7497 if (fOutOfBandParameter == kNotifyCapabilityChangeApps)
7498 {
7499 MS_POP(); // tellSystemCapabilityChange()
7500 continue;
7501 }
7502 fOutOfBandParameter = kNotifyCapabilityChangeApps;
7503 }
7504 tellClientsWithResponse( fOutOfBandMessage );
b0d623f7
A
7505 break;
7506
2d21ac55 7507 default:
b0d623f7
A
7508 panic("servicePMWorkQueue: unknown machine state %x",
7509 fMachineState);
2d21ac55
A
7510 }
7511
b0d623f7 7512 gIOPMRequest = 0;
2d21ac55
A
7513
7514 if (fMachineState == kIOPM_Finished)
7515 {
39236c6e 7516 stop_watchdog_timer();
2d21ac55
A
7517 done = true;
7518 break;
7519 }
7520 }
1c79356b 7521
2d21ac55
A
7522 return done;
7523}
1c79356b 7524
1c79356b 7525//*********************************************************************************
2d21ac55
A
7526// [private] executePMRequest
7527//*********************************************************************************
7528
7529void IOService::executePMRequest( IOPMRequest * request )
7530{
7531 assert( kIOPM_Finished == fMachineState );
7532
7533 switch (request->getType())
7534 {
7535 case kIOPMRequestTypePMStop:
7536 handlePMstop( request );
7537 break;
7538
7539 case kIOPMRequestTypeAddPowerChild1:
7540 addPowerChild1( request );
7541 break;
7542
7543 case kIOPMRequestTypeAddPowerChild2:
7544 addPowerChild2( request );
7545 break;
7546
7547 case kIOPMRequestTypeAddPowerChild3:
7548 addPowerChild3( request );
7549 break;
7550
7551 case kIOPMRequestTypeRegisterPowerDriver:
7552 handleRegisterPowerDriver( request );
7553 break;
7554
7555 case kIOPMRequestTypeAdjustPowerState:
b0d623f7 7556 fAdjustPowerScheduled = false;
2d21ac55
A
7557 adjustPowerState();
7558 break;
7559
2d21ac55
A
7560 case kIOPMRequestTypePowerDomainWillChange:
7561 handlePowerDomainWillChangeTo( request );
7562 break;
7563
7564 case kIOPMRequestTypePowerDomainDidChange:
7565 handlePowerDomainDidChangeTo( request );
7566 break;
7567
b0d623f7
A
7568 case kIOPMRequestTypeRequestPowerState:
7569 case kIOPMRequestTypeRequestPowerStateOverride:
7570 handleRequestPowerState( request );
2d21ac55
A
7571 break;
7572
7573 case kIOPMRequestTypePowerOverrideOnPriv:
7574 case kIOPMRequestTypePowerOverrideOffPriv:
7575 handlePowerOverrideChanged( request );
7576 break;
7577
7578 case kIOPMRequestTypeActivityTickle:
b0d623f7
A
7579 handleActivityTickle( request );
7580 break;
2d21ac55 7581
b0d623f7
A
7582 case kIOPMRequestTypeSynchronizePowerTree:
7583 handleSynchronizePowerTree( request );
7584 break;
7585
7586 case kIOPMRequestTypeSetIdleTimerPeriod:
7587 {
b0d623f7 7588 fIdleTimerPeriod = (uintptr_t) request->fArg0;
6d2010ae 7589 if ((false == fLockedFlags.PMStop) && (fIdleTimerPeriod > 0))
bd504ef0 7590 restartIdleTimer();
b0d623f7
A
7591 }
7592 break;
2d21ac55 7593
7ddcb079
A
7594 case kIOPMRequestTypeIgnoreIdleTimer:
7595 fIdleTimerIgnored = request->fArg0 ? 1 : 0;
7596 break;
7597
2d21ac55 7598 default:
b0d623f7 7599 panic("executePMRequest: unknown request type %x", request->getType());
2d21ac55
A
7600 }
7601}
7602
7603//*********************************************************************************
7604// [private] servicePMReplyQueue
7605//*********************************************************************************
7606
7607bool IOService::servicePMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
7608{
7609 bool more = false;
7610
7611 assert( request && queue );
b0d623f7 7612 assert( request->isReplyType() );
2d21ac55 7613
6d2010ae 7614 PM_LOG1("[A %02x] %p [%p %s] state %d\n",
39236c6e
A
7615 request->getType(), OBFUSCATE(request),
7616 OBFUSCATE(this), getName(), fMachineState);
2d21ac55
A
7617
7618 switch ( request->getType() )
7619 {
7620 case kIOPMRequestTypeAllowPowerChange:
7621 case kIOPMRequestTypeCancelPowerChange:
7622 // Check if we are expecting this response.
6d2010ae
A
7623 if (responseValid((uint32_t)(uintptr_t) request->fArg0,
7624 (int)(uintptr_t) request->fArg1))
2d21ac55
A
7625 {
7626 if (kIOPMRequestTypeCancelPowerChange == request->getType())
b0d623f7 7627 {
6d2010ae
A
7628 // Clients are not allowed to cancel when kIOPMSkipAskPowerDown
7629 // flag is set. Only root domain will set this flag.
39236c6e
A
7630 // However, there is one exception to this rule. User-space PM
7631 // policy may choose to cancel sleep even after all clients have
7632 // been notified that we will lower power.
6d2010ae 7633
39236c6e
A
7634 if ((fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
7635 || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
7636 || ((fHeadNoteChangeFlags & kIOPMSkipAskPowerDown) == 0))
6d2010ae
A
7637 {
7638 fDoNotPowerDown = true;
b0d623f7 7639
6d2010ae
A
7640 OSString * name = (OSString *) request->fArg2;
7641 getPMRootDomain()->pmStatsRecordApplicationResponse(
7642 gIOPMStatsApplicationResponseCancel,
7643 name ? name->getCStringNoCopy() : "", 0,
7644 0, (int)(uintptr_t) request->fArg1);
7645 }
b0d623f7 7646 }
2d21ac55
A
7647
7648 if (checkForDone())
7649 {
7650 stop_ack_timer();
6d2010ae 7651 cleanClientResponses(false);
2d21ac55
A
7652 more = true;
7653 }
7654 }
b0d623f7
A
7655 // OSString containing app name in Arg2 must be released.
7656 if (request->getType() == kIOPMRequestTypeCancelPowerChange)
7657 {
7658 OSObject * obj = (OSObject *) request->fArg2;
7659 if (obj) obj->release();
7660 }
2d21ac55
A
7661 break;
7662
7663 case kIOPMRequestTypeAckPowerChange:
7664 more = handleAcknowledgePowerChange( request );
7665 break;
7666
7667 case kIOPMRequestTypeAckSetPowerState:
7668 if (fDriverTimer == -1)
7669 {
7670 // driver acked while setPowerState() call is in-flight.
7671 // take this ack, return value from setPowerState() is irrelevant.
7672 OUR_PMLog(kPMLogDriverAcknowledgeSet,
b0d623f7 7673 (uintptr_t) this, fDriverTimer);
2d21ac55
A
7674 fDriverTimer = 0;
7675 }
7676 else if (fDriverTimer > 0)
7677 {
7678 // expected ack, stop the timer
7679 stop_ack_timer();
7680
7681#if LOG_SETPOWER_TIMES
7682 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
7683 if (nsec > LOG_SETPOWER_TIMES)
6d2010ae 7684 PM_LOG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
39236c6e 7685 fName, OBFUSCATE(this), fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
6d2010ae
A
7686
7687 PMEventDetails *details = PMEventDetails::eventDetails(
7688 kIOPMEventTypeSetPowerStateDelayed, // type
7689 fName, // who
7690 (uintptr_t)this, // owner unique
7691 NULL, // interest name
7692 (uint8_t)getPowerState(), // old
7693 (uint8_t)fHeadNotePowerState, // new
7694 0, // result
7695 NS_TO_US(nsec)); // usec completion time
7696
39236c6e 7697 getPMRootDomain()->recordAndReleasePMEvent( details );
2d21ac55 7698#endif
b0d623f7 7699 OUR_PMLog(kPMLogDriverAcknowledgeSet, (uintptr_t) this, fDriverTimer);
2d21ac55
A
7700 fDriverTimer = 0;
7701 more = true;
7702 }
7703 else
7704 {
7705 // unexpected ack
b0d623f7 7706 OUR_PMLog(kPMLogAcknowledgeErr4, (uintptr_t) this, 0);
2d21ac55
A
7707 }
7708 break;
7709
7710 case kIOPMRequestTypeInterestChanged:
7711 handleInterestChanged( request );
7712 more = true;
7713 break;
7714
593a1d5f 7715 case kIOPMRequestTypeIdleCancel:
39236c6e
A
7716 if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown)
7717 || (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
6d2010ae
A
7718 || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
7719 || (fMachineState == kIOPM_SyncTellClientsPowerDown)
7720 || (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown))
593a1d5f 7721 {
6d2010ae
A
7722 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7723 PM_LOG2("%s: cancel from machine state %d\n",
7724 getName(), fMachineState);
593a1d5f 7725 fDoNotPowerDown = true;
6d2010ae
A
7726 // Stop waiting for app replys.
7727 if ((fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown) ||
39236c6e
A
7728 (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown) ||
7729 (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown))
593a1d5f
A
7730 cleanClientResponses(false);
7731 more = true;
7732 }
7733 break;
593a1d5f 7734
6d2010ae
A
7735 case kIOPMRequestTypeChildNotifyDelayCancel:
7736 if (fMachineState == kIOPM_NotifyChildrenDelayed)
7737 {
7738 PM_LOG2("%s: delay notify cancelled\n", getName());
7739 notifyChildrenDelayed();
7740 }
7741 break;
7742
2d21ac55 7743 default:
b0d623f7
A
7744 panic("servicePMReplyQueue: unknown reply type %x",
7745 request->getType());
2d21ac55
A
7746 }
7747
6d2010ae
A
7748 more |= gIOPMFreeQueue->queuePMRequest(request);
7749 if (more)
7750 gIOPMWorkQueue->incrementProducerCount();
7751
2d21ac55
A
7752 return more;
7753}
7754
b0d623f7 7755//*********************************************************************************
6d2010ae 7756// [private] assertPMDriverCall / deassertPMDriverCall
b0d623f7
A
7757//*********************************************************************************
7758
6d2010ae
A
7759bool IOService::assertPMDriverCall(
7760 IOPMDriverCallEntry * entry,
7761 IOOptionBits options,
7762 IOPMinformee * inform )
b0d623f7 7763{
6d2010ae
A
7764 IOService * target = 0;
7765 bool ok = false;
7766
b0d623f7
A
7767 if (!initialized)
7768 return false;
7769
b0d623f7 7770 PM_LOCK();
6d2010ae 7771
b0d623f7
A
7772 if (fLockedFlags.PMStop)
7773 {
6d2010ae
A
7774 goto fail;
7775 }
7776
7777 if (((options & kIOPMADC_NoInactiveCheck) == 0) && isInactive())
7778 {
7779 goto fail;
7780 }
7781
7782 if (inform)
7783 {
7784 if (!inform->active)
7785 {
7786 goto fail;
7787 }
7788 target = inform->whatObject;
7789 if (target->isInactive())
7790 {
7791 goto fail;
7792 }
b0d623f7
A
7793 }
7794
6d2010ae
A
7795 entry->thread = current_thread();
7796 entry->target = target;
7797 queue_enter(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
7798 ok = true;
7799
7800fail:
b0d623f7
A
7801 PM_UNLOCK();
7802
6d2010ae 7803 return ok;
b0d623f7
A
7804}
7805
6d2010ae 7806void IOService::deassertPMDriverCall( IOPMDriverCallEntry * entry )
b0d623f7 7807{
6d2010ae
A
7808 bool wakeup = false;
7809
b0d623f7 7810 PM_LOCK();
6d2010ae
A
7811
7812 assert( !queue_empty(&fPMDriverCallQueue) );
7813 queue_remove(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
7814 if (fLockedFlags.PMDriverCallWait)
b0d623f7 7815 {
6d2010ae 7816 wakeup = true;
b0d623f7 7817 }
6d2010ae 7818
b0d623f7 7819 PM_UNLOCK();
6d2010ae
A
7820
7821 if (wakeup)
7822 PM_LOCK_WAKEUP(&fPMDriverCallQueue);
7823}
7824
7825void IOService::waitForPMDriverCall( IOService * target )
7826{
7827 const IOPMDriverCallEntry * entry;
7828 thread_t thread = current_thread();
7829 AbsoluteTime deadline;
7830 int waitResult;
7831 bool log = true;
7832 bool wait;
7833
7834 do {
7835 wait = false;
7836 queue_iterate(&fPMDriverCallQueue, entry, const IOPMDriverCallEntry *, link)
7837 {
7838 // Target of interested driver call
7839 if (target && (target != entry->target))
7840 continue;
7841
7842 if (entry->thread == thread)
7843 {
7844 if (log)
7845 {
7846 PM_LOG("%s: %s(%s) on PM thread\n",
7847 fName, __FUNCTION__, target ? target->getName() : "");
7848 OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
7849 fName, __FUNCTION__, target ? target->getName() : "");
7850 log = false;
7851 }
7852 continue;
7853 }
7854
7855 wait = true;
7856 break;
7857 }
7858
7859 if (wait)
7860 {
7861 fLockedFlags.PMDriverCallWait = true;
7862 clock_interval_to_deadline(15, kSecondScale, &deadline);
7863 waitResult = PM_LOCK_SLEEP(&fPMDriverCallQueue, deadline);
7864 fLockedFlags.PMDriverCallWait = false;
7865 if (THREAD_TIMED_OUT == waitResult)
7866 {
7867 PM_ERROR("%s: waitForPMDriverCall timeout\n", fName);
7868 wait = false;
7869 }
7870 }
7871 } while (wait);
7872}
7873
7874//*********************************************************************************
7875// [private] Debug helpers
7876//*********************************************************************************
7877
7878const char * IOService::getIOMessageString( uint32_t msg )
7879{
39236c6e 7880#define MSG_ENTRY(x) {(int) x, #x}
6d2010ae
A
7881
7882 static const IONamedValue msgNames[] = {
7883 MSG_ENTRY( kIOMessageCanDevicePowerOff ),
7884 MSG_ENTRY( kIOMessageDeviceWillPowerOff ),
7885 MSG_ENTRY( kIOMessageDeviceWillNotPowerOff ),
7886 MSG_ENTRY( kIOMessageDeviceHasPoweredOn ),
7887 MSG_ENTRY( kIOMessageCanSystemPowerOff ),
7888 MSG_ENTRY( kIOMessageSystemWillPowerOff ),
7889 MSG_ENTRY( kIOMessageSystemWillNotPowerOff ),
7890 MSG_ENTRY( kIOMessageCanSystemSleep ),
7891 MSG_ENTRY( kIOMessageSystemWillSleep ),
7892 MSG_ENTRY( kIOMessageSystemWillNotSleep ),
7893 MSG_ENTRY( kIOMessageSystemHasPoweredOn ),
7894 MSG_ENTRY( kIOMessageSystemWillRestart ),
7895 MSG_ENTRY( kIOMessageSystemWillPowerOn ),
39236c6e
A
7896 MSG_ENTRY( kIOMessageSystemCapabilityChange ),
7897 MSG_ENTRY( kIOPMMessageLastCallBeforeSleep )
6d2010ae
A
7898 };
7899
7900 return IOFindNameForValue(msg, msgNames);
b0d623f7
A
7901}
7902
39236c6e 7903
7e4a7d39
A
7904// MARK: -
7905// MARK: IOPMRequest
7906
2d21ac55
A
7907//*********************************************************************************
7908// IOPMRequest Class
7909//
7910// Requests from PM clients, and also used for inter-object messaging within PM.
7911//*********************************************************************************
7912
7913OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
7914
7915IOPMRequest * IOPMRequest::create( void )
7916{
7917 IOPMRequest * me = OSTypeAlloc(IOPMRequest);
7918 if (me && !me->init(0, kIOPMRequestTypeInvalid))
7919 {
7920 me->release();
7921 me = 0;
7922 }
7923 return me;
7924}
7925
7926bool IOPMRequest::init( IOService * target, IOOptionBits type )
7927{
7928 if (!IOCommand::init())
7929 return false;
7930
b0d623f7
A
7931 fType = type;
7932 fTarget = target;
39236c6e 7933#if NOT_READY
b0d623f7 7934 fCompletionStatus = kIOReturnSuccess;
39236c6e 7935#endif
2d21ac55
A
7936
7937 if (fTarget)
7938 fTarget->retain();
7939
7940 return true;
7941}
7942
7943void IOPMRequest::reset( void )
7944{
b0d623f7
A
7945 assert( fWorkWaitCount == 0 );
7946 assert( fFreeWaitCount == 0 );
7947
7948 detachNextRequest();
7949 detachRootRequest();
2d21ac55
A
7950
7951 fType = kIOPMRequestTypeInvalid;
7952
bd504ef0 7953#if NOT_READY
b0d623f7 7954 if (fCompletionAction)
2d21ac55 7955 {
b0d623f7
A
7956 fCompletionAction(fCompletionTarget, fCompletionParam, fCompletionStatus);
7957 }
bd504ef0 7958#endif
2d21ac55
A
7959
7960 if (fTarget)
7961 {
7962 fTarget->release();
7963 fTarget = 0;
b0d623f7
A
7964 }
7965}
7966
6d2010ae 7967bool IOPMRequest::attachNextRequest( IOPMRequest * next )
b0d623f7 7968{
6d2010ae
A
7969 bool ok = false;
7970
b0d623f7
A
7971 if (!fRequestNext)
7972 {
7973 // Postpone the execution of the next request after
7974 // this request.
7975 fRequestNext = next;
7976 fRequestNext->fWorkWaitCount++;
7977#if LOG_REQUEST_ATTACH
bd504ef0 7978 PM_LOG("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
39236c6e 7979 OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestNext),
b0d623f7
A
7980 (uint32_t) fRequestNext->fType,
7981 (uint32_t) fRequestNext->fWorkWaitCount,
7982 fTarget->getName());
7983#endif
6d2010ae 7984 ok = true;
b0d623f7 7985 }
6d2010ae 7986 return ok;
b0d623f7
A
7987}
7988
6d2010ae 7989bool IOPMRequest::detachNextRequest( void )
b0d623f7 7990{
6d2010ae
A
7991 bool ok = false;
7992
b0d623f7
A
7993 if (fRequestNext)
7994 {
7995 assert(fRequestNext->fWorkWaitCount);
7996 if (fRequestNext->fWorkWaitCount)
7997 fRequestNext->fWorkWaitCount--;
7998#if LOG_REQUEST_ATTACH
bd504ef0 7999 PM_LOG("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
39236c6e 8000 OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestNext),
b0d623f7
A
8001 (uint32_t) fRequestNext->fType,
8002 (uint32_t) fRequestNext->fWorkWaitCount,
8003 fTarget->getName());
8004#endif
8005 fRequestNext = 0;
6d2010ae 8006 ok = true;
b0d623f7 8007 }
6d2010ae 8008 return ok;
b0d623f7
A
8009}
8010
6d2010ae 8011bool IOPMRequest::attachRootRequest( IOPMRequest * root )
b0d623f7 8012{
6d2010ae
A
8013 bool ok = false;
8014
b0d623f7
A
8015 if (!fRequestRoot)
8016 {
8017 // Delay the completion of the root request after
8018 // this request.
8019 fRequestRoot = root;
8020 fRequestRoot->fFreeWaitCount++;
8021#if LOG_REQUEST_ATTACH
bd504ef0 8022 PM_LOG("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
39236c6e 8023 OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
b0d623f7
A
8024 (uint32_t) fRequestRoot->fType,
8025 (uint32_t) fRequestRoot->fFreeWaitCount,
8026 fTarget->getName());
8027#endif
6d2010ae 8028 ok = true;
b0d623f7 8029 }
6d2010ae 8030 return ok;
b0d623f7
A
8031}
8032
6d2010ae 8033bool IOPMRequest::detachRootRequest( void )
b0d623f7 8034{
6d2010ae
A
8035 bool ok = false;
8036
b0d623f7
A
8037 if (fRequestRoot)
8038 {
8039 assert(fRequestRoot->fFreeWaitCount);
8040 if (fRequestRoot->fFreeWaitCount)
8041 fRequestRoot->fFreeWaitCount--;
8042#if LOG_REQUEST_ATTACH
bd504ef0 8043 PM_LOG("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
39236c6e 8044 OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
b0d623f7
A
8045 (uint32_t) fRequestRoot->fType,
8046 (uint32_t) fRequestRoot->fFreeWaitCount,
8047 fTarget->getName());
8048#endif
8049 fRequestRoot = 0;
6d2010ae 8050 ok = true;
b0d623f7 8051 }
6d2010ae 8052 return ok;
2d21ac55
A
8053}
8054
7e4a7d39
A
8055// MARK: -
8056// MARK: IOPMRequestQueue
8057
2d21ac55
A
8058//*********************************************************************************
8059// IOPMRequestQueue Class
1c79356b 8060//
6d2010ae 8061// Global queues. Queues are created once and never released.
1c79356b 8062//*********************************************************************************
2d21ac55
A
8063
8064OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
8065
8066IOPMRequestQueue * IOPMRequestQueue::create( IOService * inOwner, Action inAction )
1c79356b 8067{
2d21ac55
A
8068 IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
8069 if (me && !me->init(inOwner, inAction))
8070 {
8071 me->release();
8072 me = 0;
8073 }
8074 return me;
8075}
1c79356b 8076
2d21ac55
A
8077bool IOPMRequestQueue::init( IOService * inOwner, Action inAction )
8078{
8079 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
1c79356b
A
8080 return false;
8081
2d21ac55
A
8082 queue_init(&fQueue);
8083 fLock = IOLockAlloc();
8084 return (fLock != 0);
8085}
1c79356b 8086
2d21ac55
A
8087void IOPMRequestQueue::free( void )
8088{
8089 if (fLock)
8090 {
8091 IOLockFree(fLock);
8092 fLock = 0;
8093 }
8094 return IOEventSource::free();
8095}
1c79356b 8096
2d21ac55
A
8097void IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
8098{
8099 assert(request);
8100 IOLockLock(fLock);
8101 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
8102 IOLockUnlock(fLock);
8103 if (workLoop) signalWorkAvailable();
8104}
1c79356b 8105
2d21ac55
A
8106void
8107IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
8108{
8109 IOPMRequest * next;
8110
8111 assert(requests && count);
8112 IOLockLock(fLock);
8113 while (count--)
8114 {
8115 next = *requests;
8116 requests++;
8117 queue_enter(&fQueue, next, IOPMRequest *, fCommandChain);
8118 }
8119 IOLockUnlock(fLock);
8120 if (workLoop) signalWorkAvailable();
8121}
8122
8123bool IOPMRequestQueue::checkForWork( void )
8124{
8125 Action dqAction = (Action) action;
8126 IOPMRequest * request;
8127 IOService * target;
8128 bool more = false;
8129
8130 IOLockLock( fLock );
8131
8132 while (!queue_empty(&fQueue))
8133 {
8134 queue_remove_first( &fQueue, request, IOPMRequest *, fCommandChain );
8135 IOLockUnlock( fLock );
8136 target = request->getTarget();
8137 assert(target);
8138 more |= (*dqAction)( target, request, this );
8139 IOLockLock( fLock );
8140 }
8141
8142 IOLockUnlock( fLock );
8143 return more;
8144}
8145
7e4a7d39
A
8146// MARK: -
8147// MARK: IOPMWorkQueue
8148
2d21ac55
A
8149//*********************************************************************************
8150// IOPMWorkQueue Class
8151//
6d2010ae 8152// Queue of IOServicePM objects with busy IOPMRequest(s).
2d21ac55 8153//*********************************************************************************
1c79356b 8154
2d21ac55 8155OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
1c79356b 8156
2d21ac55
A
8157IOPMWorkQueue *
8158IOPMWorkQueue::create( IOService * inOwner, Action work, Action retire )
8159{
8160 IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
8161 if (me && !me->init(inOwner, work, retire))
8162 {
8163 me->release();
8164 me = 0;
8165 }
8166 return me;
8167}
8168
8169bool IOPMWorkQueue::init( IOService * inOwner, Action work, Action retire )
8170{
8171 if (!work || !retire ||
8172 !IOEventSource::init(inOwner, (IOEventSourceAction)0))
8173 return false;
8174
8175 queue_init(&fWorkQueue);
8176
6d2010ae
A
8177 fWorkAction = work;
8178 fRetireAction = retire;
8179 fConsumerCount = fProducerCount = 0;
2d21ac55
A
8180
8181 return true;
8182}
8183
6d2010ae 8184bool IOPMWorkQueue::queuePMRequest( IOPMRequest * request, IOServicePM * pwrMgt )
2d21ac55 8185{
6d2010ae
A
8186 bool more = false;
8187 bool empty;
8188
2d21ac55 8189 assert( request );
6d2010ae 8190 assert( pwrMgt );
2d21ac55 8191 assert( onThread() );
6d2010ae
A
8192 assert( queue_next(&request->fCommandChain) ==
8193 queue_prev(&request->fCommandChain) );
2d21ac55
A
8194
8195 gIOPMBusyCount++;
6d2010ae
A
8196
8197 // Add new request to the tail of the per-service request queue.
8198 // Then immediately check the request queue to minimize latency
8199 // if the queue was empty.
8200
8201 empty = queue_empty(&pwrMgt->RequestHead);
8202 queue_enter(&pwrMgt->RequestHead, request, IOPMRequest *, fCommandChain);
8203 if (empty)
8204 {
8205 more = checkRequestQueue(&pwrMgt->RequestHead, &empty);
8206 if (!empty)
8207 {
8208 // New Request is blocked, add IOServicePM to work queue.
8209 assert( queue_next(&pwrMgt->WorkChain) ==
8210 queue_prev(&pwrMgt->WorkChain) );
8211
8212 queue_enter(&fWorkQueue, pwrMgt, IOServicePM *, WorkChain);
8213 fQueueLength++;
8214 PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
39236c6e 8215 fQueueLength, pwrMgt->Name, OBFUSCATE(pwrMgt));
6d2010ae
A
8216 }
8217 }
8218
8219 return more;
2d21ac55
A
8220}
8221
6d2010ae 8222bool IOPMWorkQueue::checkRequestQueue( queue_head_t * queue, bool * empty )
2d21ac55
A
8223{
8224 IOPMRequest * request;
6d2010ae
A
8225 IOService * target;
8226 bool more = false;
8227 bool done = false;
2d21ac55 8228
6d2010ae
A
8229 assert(!queue_empty(queue));
8230 do {
8231 request = (IOPMRequest *) queue_first(queue);
8232 if (request->isWorkBlocked())
8233 break; // cannot start, blocked on attached request
2d21ac55 8234
6d2010ae
A
8235 target = request->getTarget();
8236 done = (*fWorkAction)( target, request, this );
8237 if (!done)
8238 break; // work started, blocked on PM state machine
8239
8240 assert(gIOPMBusyCount > 0);
8241 if (gIOPMBusyCount)
8242 gIOPMBusyCount--;
8243
8244 queue_remove_first(queue, request, IOPMRequest *, fCommandChain);
8245 more |= (*fRetireAction)( target, request, this );
8246 done = queue_empty(queue);
8247 } while (!done);
8248
8249 *empty = done;
8250
8251 if (more)
8252 {
8253 // Retired request blocks another request, since the
8254 // blocked request may reside in the work queue, we
8255 // must bump the producer count to avoid work stall.
8256 fProducerCount++;
8257 }
8258
8259 return more;
8260}
8261
8262bool IOPMWorkQueue::checkForWork( void )
8263{
8264 IOServicePM * entry;
8265 IOServicePM * next;
8266 bool more = false;
8267 bool empty;
8268
8269#if WORK_QUEUE_STATS
8270 fStatCheckForWork++;
8271#endif
8272
8273 // Each producer signal triggers a full iteration over
8274 // all IOServicePM entries in the work queue.
8275
8276 while (fConsumerCount != fProducerCount)
8277 {
8278 PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
8279 fProducerCount, fConsumerCount);
8280
8281 fConsumerCount = fProducerCount;
8282
8283#if WORK_QUEUE_STATS
8284 if (queue_empty(&fWorkQueue))
8285 {
8286 fStatQueueEmpty++;
8287 break;
8288 }
8289 fStatScanEntries++;
8290 uint32_t cachedWorkCount = gIOPMWorkCount;
8291#endif
8292
8293 entry = (IOServicePM *) queue_first(&fWorkQueue);
8294 while (!queue_end(&fWorkQueue, (queue_entry_t) entry))
8295 {
8296 more |= checkRequestQueue(&entry->RequestHead, &empty);
8297
8298 // Get next entry, points to head if current entry is last.
8299 next = (IOServicePM *) queue_next(&entry->WorkChain);
8300
8301 // if request queue is empty, remove IOServicePM from queue.
8302 if (empty)
8303 {
8304 assert(fQueueLength);
8305 if (fQueueLength) fQueueLength--;
8306 PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
39236c6e 8307 fQueueLength, entry->Name, OBFUSCATE(entry));
6d2010ae
A
8308 queue_remove(&fWorkQueue, entry, IOServicePM *, WorkChain);
8309 }
8310 entry = next;
8311 }
8312
8313#if WORK_QUEUE_STATS
8314 if (cachedWorkCount == gIOPMWorkCount)
8315 fStatNoWorkDone++;
8316#endif
8317 }
8318
8319 return more;
8320}
8321
8322void IOPMWorkQueue::signalWorkAvailable( void )
8323{
8324 fProducerCount++;
8325 IOEventSource::signalWorkAvailable();
8326}
8327
8328void IOPMWorkQueue::incrementProducerCount( void )
8329{
8330 fProducerCount++;
2d21ac55
A
8331}
8332
7e4a7d39
A
8333// MARK: -
8334// MARK: IOPMCompletionQueue
8335
b0d623f7
A
8336//*********************************************************************************
8337// IOPMCompletionQueue Class
8338//*********************************************************************************
8339
8340OSDefineMetaClassAndStructors( IOPMCompletionQueue, IOEventSource );
8341
6d2010ae
A
8342IOPMCompletionQueue *
8343IOPMCompletionQueue::create( IOService * inOwner, Action inAction )
b0d623f7
A
8344{
8345 IOPMCompletionQueue * me = OSTypeAlloc(IOPMCompletionQueue);
8346 if (me && !me->init(inOwner, inAction))
8347 {
8348 me->release();
8349 me = 0;
8350 }
8351 return me;
8352}
8353
8354bool IOPMCompletionQueue::init( IOService * inOwner, Action inAction )
8355{
8356 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
8357 return false;
8358
8359 queue_init(&fQueue);
8360 return true;
8361}
8362
6d2010ae 8363bool IOPMCompletionQueue::queuePMRequest( IOPMRequest * request )
b0d623f7 8364{
6d2010ae
A
8365 bool more;
8366
b0d623f7 8367 assert(request);
6d2010ae
A
8368 // unblock dependent request
8369 more = request->detachNextRequest();
b0d623f7 8370 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
6d2010ae 8371 return more;
b0d623f7
A
8372}
8373
8374bool IOPMCompletionQueue::checkForWork( void )
8375{
8376 Action dqAction = (Action) action;
8377 IOPMRequest * request;
6d2010ae 8378 IOPMRequest * next;
b0d623f7
A
8379 IOService * target;
8380 bool more = false;
b0d623f7 8381
6d2010ae
A
8382 request = (IOPMRequest *) queue_first(&fQueue);
8383 while (!queue_end(&fQueue, (queue_entry_t) request))
8384 {
8385 next = (IOPMRequest *) queue_next(&request->fCommandChain);
8386 if (!request->isFreeBlocked())
8387 {
8388 queue_remove(&fQueue, request, IOPMRequest *, fCommandChain);
8389 target = request->getTarget();
8390 assert(target);
8391 more |= (*dqAction)( target, request, this );
8392 }
8393 request = next;
8394 }
b0d623f7 8395
6d2010ae 8396 return more;
b0d623f7
A
8397}
8398
7e4a7d39
A
8399// MARK: -
8400// MARK: IOServicePM
8401
2d21ac55
A
8402OSDefineMetaClassAndStructors(IOServicePM, OSObject)
8403
8404//*********************************************************************************
8405// serialize
8406//
8407// Serialize IOServicePM for debugging.
8408//*********************************************************************************
8409
8410static void
b0d623f7 8411setPMProperty( OSDictionary * dict, const char * key, uint64_t value )
2d21ac55
A
8412{
8413 OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
8414 if (num)
8415 {
8416 dict->setObject(key, num);
8417 num->release();
8418 }
1c79356b
A
8419}
8420
39236c6e 8421IOReturn IOServicePM::gatedSerialize( OSSerialize * s ) const
2d21ac55
A
8422{
8423 OSDictionary * dict;
8424 bool ok = false;
39236c6e 8425 int powerClamp = -1;
6d2010ae 8426 int dictSize = 5;
b0d623f7
A
8427
8428 if (IdleTimerPeriod)
8429 dictSize += 4;
8430
39236c6e
A
8431 if (PMActions.parameter & kPMActionsFlagLimitPower)
8432 {
8433 dictSize += 1;
8434 powerClamp = 0;
8435 if (PMActions.parameter &
8436 (kPMActionsFlagIsDisplayWrangler | kPMActionsFlagIsGraphicsDevice))
8437 powerClamp++;
8438 }
8439
6d2010ae
A
8440#if WORK_QUEUE_STATS
8441 if (gIOPMRootNode == ControllingDriver)
8442 dictSize += 4;
8443#endif
8444
b0d623f7
A
8445 if (PowerClients)
8446 dict = OSDictionary::withDictionary(
8447 PowerClients, PowerClients->getCount() + dictSize);
8448 else
8449 dict = OSDictionary::withCapacity(dictSize);
2d21ac55 8450
2d21ac55
A
8451 if (dict)
8452 {
b0d623f7 8453 setPMProperty(dict, "CurrentPowerState", CurrentPowerState);
6d2010ae
A
8454 if (NumberOfPowerStates)
8455 setPMProperty(dict, "MaxPowerState", NumberOfPowerStates-1);
2d21ac55 8456 if (DesiredPowerState != CurrentPowerState)
b0d623f7 8457 setPMProperty(dict, "DesiredPowerState", DesiredPowerState);
2d21ac55 8458 if (kIOPM_Finished != MachineState)
b0d623f7 8459 setPMProperty(dict, "MachineState", MachineState);
6d2010ae 8460 if (DeviceOverrideEnabled)
b0d623f7 8461 dict->setObject("PowerOverrideOn", kOSBooleanTrue);
39236c6e
A
8462 if (powerClamp >= 0)
8463 setPMProperty(dict, "PowerClamp", powerClamp);
b0d623f7
A
8464
8465 if (IdleTimerPeriod)
8466 {
8467 AbsoluteTime now;
8468 AbsoluteTime delta;
8469 uint64_t nsecs;
8470
8471 clock_get_uptime(&now);
8472
8473 // The idle timer period in milliseconds.
8474 setPMProperty(dict, "IdleTimerPeriod", IdleTimerPeriod * 1000ULL);
8475
8476 // The number of activity tickles recorded since device idle
8477 setPMProperty(dict, "ActivityTickles", ActivityTickleCount);
8478
8479 if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp))
8480 {
8481 // The number of milliseconds since the last activity tickle.
8482 delta = now;
8483 SUB_ABSOLUTETIME(&delta, &DeviceActiveTimestamp);
8484 absolutetime_to_nanoseconds(delta, &nsecs);
6d2010ae 8485 setPMProperty(dict, "TimeSinceLastTickle", NS_TO_MS(nsecs));
b0d623f7
A
8486 }
8487
8488 if (AbsoluteTime_to_scalar(&IdleTimerStartTime))
8489 {
8490 // The number of milliseconds since the last device idle.
8491 delta = now;
8492 SUB_ABSOLUTETIME(&delta, &IdleTimerStartTime);
8493 absolutetime_to_nanoseconds(delta, &nsecs);
8494 setPMProperty(dict, "TimeSinceDeviceIdle", NS_TO_MS(nsecs));
8495 }
8496 }
2d21ac55 8497
6d2010ae
A
8498#if WORK_QUEUE_STATS
8499 if (gIOPMRootNode == Owner)
8500 {
8501 setPMProperty(dict, "WQ-CheckForWork",
8502 gIOPMWorkQueue->fStatCheckForWork);
8503 setPMProperty(dict, "WQ-ScanEntries",
8504 gIOPMWorkQueue->fStatScanEntries);
8505 setPMProperty(dict, "WQ-QueueEmpty",
8506 gIOPMWorkQueue->fStatQueueEmpty);
8507 setPMProperty(dict, "WQ-NoWorkDone",
8508 gIOPMWorkQueue->fStatNoWorkDone);
8509 }
8510#endif
8511
db609669
A
8512 if (HasAdvisoryDesire && !gIOPMAdvisoryTickleEnabled)
8513 {
8514 // Don't report advisory tickle when it has no influence
8515 dict->removeObject(gIOPMPowerClientAdvisoryTickle);
8516 }
8517
2d21ac55
A
8518 ok = dict->serialize(s);
8519 dict->release();
8520 }
8521
b0d623f7
A
8522 return (ok ? kIOReturnSuccess : kIOReturnNoMemory);
8523}
8524
8525bool IOServicePM::serialize( OSSerialize * s ) const
8526{
8527 IOReturn ret = kIOReturnNotReady;
8528
39236c6e
A
8529 if (gIOPMWatchDogThread == current_thread())
8530 {
8531 // Calling without lock as this data is collected for debug purpose, before reboot.
8532 // The workloop is probably already hung in state machine.
8533 ret = gatedSerialize(s);
8534 }
8535 else if (gIOPMWorkLoop)
b0d623f7
A
8536 {
8537 ret = gIOPMWorkLoop->runAction(
8538 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOServicePM::gatedSerialize),
8539 (OSObject *) this, (void *) s);
8540 }
8541
8542 return (kIOReturnSuccess == ret);
2d21ac55 8543}
6d2010ae 8544
4b17d6b6
A
8545void IOServicePM::pmPrint(
8546 uint32_t event,
8547 uintptr_t param1,
8548 uintptr_t param2 ) const
8549{
8550 gPlatform->PMLog(Name, event, param1, param2);
8551}
8552
8553void IOServicePM::pmTrace(
8554 uint32_t event,
8555 uintptr_t param1,
8556 uintptr_t param2 ) const
8557{
8558 const char * who = Name;
8559 uint64_t regId = Owner->getRegistryEntryID();
8560 uintptr_t name = 0;
8561
8562 static const uint32_t sStartStopBitField[] =
8563 { 0x00000000, 0x00000040 }; // Only Program Hardware so far
8564
8565 // Arcane formula from Hacker's Delight by Warren
8566 // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
8567 uint32_t sgnevent = ((int) event >> 31);
8568 uint32_t absevent = sgnevent ^ (event + sgnevent);
8569 uint32_t code = IODBG_POWER(absevent);
8570
8571 uint32_t bit = 1 << (absevent & 0x1f);
8572 if ((absevent < (sizeof(sStartStopBitField) * 8)) &&
8573 (sStartStopBitField[absevent >> 5] & bit))
8574 {
8575 // Or in the START or END bits, Start = 1 & END = 2
8576 // If sgnevent == 0 then START - 0 => START
8577 // else if sgnevent == -1 then START - -1 => END
8578 code |= DBG_FUNC_START - sgnevent;
8579 }
8580
8581 // Copy the first characters of the name into an uintptr_t
8582 for (uint32_t i = 0; (i < sizeof(uintptr_t) && who[i] != 0); i++)
8583 {
8584 ((char *) &name)[sizeof(uintptr_t) - i - 1] = who[i];
8585 }
8586
8587 IOTimeStampConstant(code, name, (uintptr_t) regId, param1, param2);
8588}
8589
6d2010ae
A
8590PMEventDetails* PMEventDetails::eventDetails(uint32_t type,
8591 const char *ownerName,
8592 uintptr_t ownerUnique,
8593 const char *interestName,
8594 uint8_t oldState,
8595 uint8_t newState,
8596 uint32_t result,
8597 uint32_t elapsedTimeUS) {
8598
8599 PMEventDetails *myself;
8600 myself = new PMEventDetails;
8601
8602 if(myself) {
8603 myself->eventType = type;
8604 myself->ownerName = ownerName;
8605 myself->ownerUnique = ownerUnique;
8606 myself->interestName = interestName;
8607 myself->oldState = oldState;
8608 myself->newState = newState;
8609 myself->result = result;
8610 myself->elapsedTimeUS = elapsedTimeUS;
8611
8612 myself->eventClassifier = kIOPMEventClassDriverEvent;
8613 }
8614
8615 return myself;
8616}
8617
8618
8619PMEventDetails* PMEventDetails::eventDetails(uint32_t type,
8620 const char *uuid,
8621 uint32_t reason,
8622 uint32_t result) {
8623
8624 PMEventDetails *myself;
8625 myself = new PMEventDetails;
8626
8627 if(myself) {
8628 myself->eventType = type;
8629 myself->uuid = uuid;
8630 myself->reason = reason;
8631 myself->result = result;
8632
8633 myself->eventClassifier = kIOPMEventClassSystemEvent;
8634 }
8635
8636 return myself;
8637}
8638