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