2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <IOKit/assert.h>
30 #include <IOKit/IOKitDebug.h>
31 #include <IOKit/IOLib.h>
32 #include <IOKit/IOMessage.h>
33 #include <IOKit/IOPlatformExpert.h>
34 #include <IOKit/IOService.h>
35 #include <IOKit/IOTimerEventSource.h>
36 #include <IOKit/IOWorkLoop.h>
37 #include <IOKit/IOCommand.h>
39 #include <IOKit/pwr_mgt/IOPMlog.h>
40 #include <IOKit/pwr_mgt/IOPMinformee.h>
41 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
42 #include <IOKit/pwr_mgt/IOPowerConnection.h>
43 #include <IOKit/pwr_mgt/RootDomain.h>
47 // Required for notification instrumentation
48 #include "IOServicePrivate.h"
49 #include "IOServicePMPrivate.h"
50 #include "IOKitKernelInternal.h"
52 static void settle_timer_expired(thread_call_param_t
, thread_call_param_t
);
53 static void PM_idle_timer_expired(OSObject
*, IOTimerEventSource
*);
54 void tellAppWithResponse(OSObject
* object
, void * context
) { /*empty*/ }
55 void tellClientWithResponse(OSObject
* object
, void * context
) { /*empty*/ }
56 void tellClient(OSObject
* object
, void * context
);
57 IOReturn
serializedAllowPowerChange(OSObject
*, void *, void *, void *, void *);
59 static uint64_t computeTimeDeltaNS( const AbsoluteTime
* start
)
64 clock_get_uptime(&now
);
65 SUB_ABSOLUTETIME(&now
, start
);
66 absolutetime_to_nanoseconds(now
, &nsec
);
70 OSDefineMetaClassAndStructors(IOPMprot
, OSObject
)
72 // log setPowerStates longer than (ns):
73 #define LOG_SETPOWER_TIMES (50ULL * 1000ULL * 1000ULL)
74 // log app responses longer than (ns):
75 #define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
77 //*********************************************************************************
79 //*********************************************************************************
81 static bool gIOPMInitialized
= false;
82 static IOItemCount gIOPMBusyCount
= 0;
83 static IOWorkLoop
* gIOPMWorkLoop
= 0;
84 static IOPMRequestQueue
* gIOPMRequestQueue
= 0;
85 static IOPMRequestQueue
* gIOPMReplyQueue
= 0;
86 static IOPMRequestQueue
* gIOPMFreeQueue
= 0;
88 //*********************************************************************************
90 //*********************************************************************************
92 #define PM_ERROR(x...) do { kprintf(x); IOLog(x); } while (false)
93 #define PM_DEBUG(x...) do { kprintf(x); } while (false)
95 #define PM_TRACE(x...) do { \
96 if (kIOLogDebugPower & gIOKitDebug) kprintf(x); } while (false)
98 #define PM_CONNECT(x...)
100 #define PM_ASSERT_IN_GATE(x) \
102 assert(gIOPMWorkLoop->inGate()); \
105 #define PM_LOCK() IOLockLock(fPMLock)
106 #define PM_UNLOCK() IOLockUnlock(fPMLock)
108 #define ns_per_us 1000
109 #define k30seconds (30*1000000)
110 #define kMinAckTimeoutTicks (10*1000000)
111 #define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
112 #define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
113 #define kPwrMgtKey "IOPowerManagement"
115 #define OUR_PMLog(t, a, b) \
116 do { fPlatform->PMLog( fName, t, a, b); } while(0)
118 #define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
121 #define SUPPORT_IDLE_CANCEL 1
124 //*********************************************************************************
126 //*********************************************************************************
129 kIOPM_OurChangeTellClientsPowerDown
= 1,
130 kIOPM_OurChangeTellPriorityClientsPowerDown
= 2,
131 kIOPM_OurChangeNotifyInterestedDriversWillChange
= 3,
132 kIOPM_OurChangeSetPowerState
= 4,
133 kIOPM_OurChangeWaitForPowerSettle
= 5,
134 kIOPM_OurChangeNotifyInterestedDriversDidChange
= 6,
135 kIOPM_OurChangeFinish
= 7,
136 kIOPM_ParentDownTellPriorityClientsPowerDown
= 8,
137 kIOPM_ParentDownNotifyInterestedDriversWillChange
= 9,
139 kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange
= 11,
140 kIOPM_ParentDownSetPowerState
= 12,
141 kIOPM_ParentDownWaitForPowerSettle
= 13,
142 kIOPM_ParentDownAcknowledgeChange
= 14,
143 kIOPM_ParentUpSetPowerState
= 15,
145 kIOPM_ParentUpWaitForSettleTime
= 17,
146 kIOPM_ParentUpNotifyInterestedDriversDidChange
= 18,
147 kIOPM_ParentUpAcknowledgePowerChange
= 19,
149 kIOPM_DriverThreadCallDone
= 21,
150 kIOPM_NotifyChildrenDone
= 22
155 Power Management defines a few roles that drivers can play in their own,
156 and other drivers', power management. We briefly define those here.
158 Many drivers implement their policy maker and power controller within the same
159 IOService object, but that is not required.
162 * Virtual IOService PM methods a "policy maker" may implement
163 * maxCapabilityForDomainState()
164 * initialPowerStateForDomainState()
165 * powerStateForDomainState()
167 * Virtual IOService PM methods a "policy maker" may CALL
170 == Power Controller ==
171 * Virtual IOService PM methods a "power controller" may implement
174 * Virtual IOService PM methods a "power controller" may CALL
176 * registerPowerDriver()
178 =======================
179 There are two different kinds of power state changes.
180 * One is initiated by a subclassed device object which has either decided
181 to change power state, or its controlling driver has suggested it, or
182 some other driver wants to use the idle device and has asked it to become
184 * The second kind of power state change is initiated by the power domain
186 The two are handled through different code paths.
188 We maintain a queue of "change notifications," or change notes.
189 * Usually the queue is empty.
190 * When it isn't, usually there is one change note in it
191 * It's possible to have more than one power state change pending at one
192 time, so a queue is implemented.
194 * The subclass device decides it's idle and initiates a change to a lower
195 power state. This causes interested parties to be notified, but they
196 don't all acknowledge right away. This causes the change note to sit
197 in the queue until all the acks are received. During this time, the
198 device decides it isn't idle anymore and wants to raise power back up
199 again. This change can't be started, however, because the previous one
200 isn't complete yet, so the second one waits in the queue. During this
201 time, the parent decides to lower or raise the power state of the entire
202 power domain and notifies the device, and that notification goes into
203 the queue, too, and can't be actioned until the others are.
206 This is how a power change initiated by the subclass device is handled:
207 -> First, all interested parties are notified of the change via their
208 powerStateWillChangeTo method. If they all don't acknowledge via return
209 code, then we have to wait. If they do, or when they finally all
210 acknowledge via our acknowledgePowerChange method, then we can continue.
211 -> We call the controlling driver, instructing it to change to the new state
212 -> Then we wait for power to settle. If there is no settling-time, or after
214 -> we notify interested parties again, this time via their
215 powerStateDidChangeTo methods.
216 -> When they have all acked, we're done.
217 If we lowered power and don't need the power domain to be in its current power
218 state, we suggest to the parent that it lower the power domain state.
220 == PowerDomainDownInitiated ==
221 How a change to a lower power domain state initiated by the parent is handled:
222 -> First, we figure out what power state we will be in when the new domain
224 -> Then all interested parties are notified that we are moving to that new
226 -> When they have acknowledged, we call the controlling driver to assume
227 that state and we wait for power to settle.
228 -> Then we acknowledge our preparedness to our parent. When all its
229 interested parties have acknowledged,
230 -> it lowers power and then notifies its interested parties again.
231 -> When we get this call, we notify our interested parties that the power
232 state has changed, and when they have all acknowledged, we're done.
234 == PowerDomainUpInitiated ==
235 How a change to a higher power domain state initiated by the parent is handled:
236 -> We figure out what power state we will be in when the new domain state is
238 -> If it is different from our current state we acknowledge the parent.
239 -> When all the parent's interested parties have acknowledged, it raises
240 power in the domain and waits for power to settle.
241 -> Then it notifies everyone that the new state has been reached.
242 -> When we get this call, we call the controlling driver, instructing it to
243 assume the new state, and wait for power to settle.
244 -> Then we notify our interested parties. When they all acknowledge we are
247 In either of the two power domain state cases above, it is possible that we
248 will not be changing state even though the domain is.
250 * A change to a lower domain state may not affect us because we are already
251 in a low enough state,
252 * We will not take advantage of a change to a higher domain state, because
253 we have no need of the higher power. In such cases, there is nothing to
254 do but acknowledge the parent. So when the parent calls our
255 powerDomainWillChange method, and we decide that we will not be changing
256 state, we merely acknowledge the parent, via return code, and wait.
257 When the parent subsequently calls powerStateDidChange, we acknowledge again
258 via return code, and the change is complete.
260 == 4 Paths Through State Machine ==
261 Power state changes are processed in a state machine, and since there are four
262 varieties of power state changes, there are four major paths through the state
265 == 5. No Need To change ==
266 The fourth is nearly trivial. In this path, the parent is changing the domain
267 state, but we are not changing the device state. The change starts when the
268 parent calls powerDomainWillChange. All we do is acknowledge the parent. When
269 the parent calls powerStateDidChange, we acknowledge the parent again, and
272 == 1. OurChange Down == XXX gvdl
273 The first is fairly simple. It starts:
274 * when a power domain child calls requestPowerDomainState and we decide to
275 change power states to accomodate the child,
276 * or if our power-controlling driver calls changePowerStateTo,
277 * or if some other driver which is using our device calls makeUsable,
278 * or if a subclassed object calls changePowerStateToPriv.
279 These are all power changes initiated by us, not forced upon us by the parent.
281 -> We start by notifying interested parties.
282 -> If they all acknowledge via return code, we can go on to state
284 -> Otherwise, we start the ack timer and wait for the stragglers to
285 acknowlege by calling acknowledgePowerChange.
286 -> We move on to state "msSetPowerState" when all the
287 stragglers have acknowledged, or when the ack timer expires on
288 all those which didn't acknowledge.
289 In "msSetPowerState" we call the power-controlling driver to change the
290 power state of the hardware.
291 -> If it returns saying it has done so, we go on to state
292 "msWaitForPowerSettle".
293 -> Otherwise, we have to wait for it, so we set the ack timer and wait.
294 -> When it calls acknowledgeSetPowerState, or when the ack timer
296 In "msWaitForPowerSettle", we look in the power state array to see if
297 there is any settle time required when changing from our current state to the
299 -> If not, we go right away to "msNotifyInterestedDriversDidChange".
300 -> Otherwise, we set the settle timer and wait. When it expires, we move on.
301 In "msNotifyInterestedDriversDidChange" state, we notify all our
302 interested parties via their powerStateDidChange methods that we have finished
303 changing power state.
304 -> If they all acknowledge via return code, we move on to "msFinish".
305 -> Otherwise we set the ack timer and wait. When they have all
306 acknowledged, or when the ack timer has expired for those that didn't,
307 we move on to "msFinish".
308 In "msFinish" we remove the used change note from the head of the queue
309 and start the next one if one exists.
311 == 2. Parent Change Down ==
312 Start at Stage 2 of OurChange Down XXX gvdl
315 Start at Stage 4 of OurChange Down XXX gvdl
317 Note all parent requested changes need to acknowledge the power has changed to the parent when done.
320 //*********************************************************************************
321 // [public virtual] PMinit
323 // Initialize power management.
324 //*********************************************************************************
326 void IOService::PMinit ( void )
330 if ( !gIOPMInitialized
)
332 gIOPMWorkLoop
= IOWorkLoop::workLoop();
335 gIOPMRequestQueue
= IOPMRequestQueue::create(
336 this, OSMemberFunctionCast(IOPMRequestQueue::Action
,
337 this, &IOService::servicePMRequestQueue
));
339 gIOPMReplyQueue
= IOPMRequestQueue::create(
340 this, OSMemberFunctionCast(IOPMRequestQueue::Action
,
341 this, &IOService::servicePMReplyQueue
));
343 gIOPMFreeQueue
= IOPMRequestQueue::create(
344 this, OSMemberFunctionCast(IOPMRequestQueue::Action
,
345 this, &IOService::servicePMFreeQueue
));
347 if (gIOPMWorkLoop
->addEventSource(gIOPMRequestQueue
) !=
350 gIOPMRequestQueue
->release();
351 gIOPMRequestQueue
= 0;
354 if (gIOPMWorkLoop
->addEventSource(gIOPMReplyQueue
) !=
357 gIOPMReplyQueue
->release();
361 if (gIOPMWorkLoop
->addEventSource(gIOPMFreeQueue
) !=
364 gIOPMFreeQueue
->release();
369 if (gIOPMRequestQueue
&& gIOPMReplyQueue
&& gIOPMFreeQueue
)
370 gIOPMInitialized
= true;
372 if (!gIOPMInitialized
)
375 pwrMgt
= new IOServicePM
;
377 setProperty(kPwrMgtKey
, pwrMgt
);
381 fPMLock
= IOLockAlloc();
382 fInterestedDrivers
= new IOPMinformeeList
;
383 fInterestedDrivers
->initialize();
384 fDesiredPowerState
= 0;
387 fInitialChange
= true;
388 fNeedToBecomeUsable
= false;
389 fPreviousRequest
= 0;
390 fDeviceOverrides
= false;
391 fMachineState
= kIOPM_Finished
;
392 fIdleTimerEventSource
= NULL
;
393 fIdleTimerMinPowerState
= 0;
394 fActivityLock
= IOLockAlloc();
396 fStrictTreeOrder
= false;
397 fActivityTicklePowerState
= -1;
398 fControllingDriver
= NULL
;
400 fNumberOfPowerStates
= 0;
401 fCurrentPowerState
= 0;
402 fParentsCurrentPowerFlags
= 0;
405 fPlatform
= getPlatform();
406 fParentsKnowState
= false;
408 fResponseArray
= NULL
;
409 fDoNotPowerDown
= true;
410 fCurrentPowerConsumption
= kIOPMUnknown
;
412 for (unsigned int i
= 0; i
<= kMaxType
; i
++)
414 fAggressivenessValue
[i
] = 0;
415 fAggressivenessValid
[i
] = false;
418 fAckTimer
= thread_call_allocate(
419 &IOService::ack_timer_expired
, (thread_call_param_t
)this);
420 fSettleTimer
= thread_call_allocate(
421 &settle_timer_expired
, (thread_call_param_t
)this);
422 fDriverCallEntry
= thread_call_allocate(
423 (thread_call_func_t
) &IOService::pmDriverCallout
, this);
424 assert(fDriverCallEntry
);
427 IOPMprot
* prot
= new IOPMprot
;
431 prot
->ourName
= fName
;
432 prot
->thePlatform
= fPlatform
;
437 pm_vars
= (IOPMprot
*) true;
444 //*********************************************************************************
447 // Free up the data created in PMinit, if it exists.
448 //*********************************************************************************
450 void IOService::PMfree ( void )
457 assert(fMachineState
== kIOPM_Finished
);
458 assert(fInsertInterestSet
== NULL
);
459 assert(fRemoveInterestSet
== NULL
);
460 assert(fNotifyChildArray
== NULL
);
462 if ( fIdleTimerEventSource
!= NULL
) {
463 getPMworkloop()->removeEventSource(fIdleTimerEventSource
);
464 fIdleTimerEventSource
->release();
465 fIdleTimerEventSource
= NULL
;
467 if ( fSettleTimer
) {
468 thread_call_cancel(fSettleTimer
);
469 thread_call_free(fSettleTimer
);
473 thread_call_cancel(fAckTimer
);
474 thread_call_free(fAckTimer
);
477 if ( fDriverCallEntry
) {
478 thread_call_free(fDriverCallEntry
);
479 fDriverCallEntry
= NULL
;
485 if ( fActivityLock
) {
486 IOLockFree(fActivityLock
);
487 fActivityLock
= NULL
;
489 if ( fInterestedDrivers
) {
490 fInterestedDrivers
->release();
491 fInterestedDrivers
= NULL
;
493 if ( fPMWorkQueue
) {
494 getPMworkloop()->removeEventSource(fPMWorkQueue
);
495 fPMWorkQueue
->release();
498 if (fDriverCallParamSlots
&& fDriverCallParamPtr
) {
499 IODelete(fDriverCallParamPtr
, DriverCallParam
, fDriverCallParamSlots
);
500 fDriverCallParamPtr
= 0;
501 fDriverCallParamSlots
= 0;
503 if ( fResponseArray
) {
504 fResponseArray
->release();
505 fResponseArray
= NULL
;
507 if (fPowerStates
&& fNumberOfPowerStates
) {
508 IODelete(fPowerStates
, IOPMPowerState
, fNumberOfPowerStates
);
509 fNumberOfPowerStates
= 0;
526 //*********************************************************************************
527 // [public virtual] joinPMtree
529 // A policy-maker calls its nub here when initializing, to be attached into
530 // the power management hierarchy. The default function is to call the
531 // platform expert, which knows how to do it. This method is overridden
532 // by a nub subclass which may either know how to do it, or may need to
533 // take other action.
535 // This may be the only "power management" method used in a nub,
536 // meaning it may not be initialized for power management.
537 //*********************************************************************************
539 void IOService::joinPMtree ( IOService
* driver
)
541 IOPlatformExpert
* platform
;
543 platform
= getPlatform();
544 assert(platform
!= 0);
545 platform
->PMRegisterDevice(this, driver
);
548 //*********************************************************************************
549 // [public virtual] youAreRoot
551 // Power Managment is informing us that we are the root power domain.
552 // The only difference between us and any other power domain is that
553 // we have no parent and therefore never call it.
554 //*********************************************************************************
556 IOReturn
IOService::youAreRoot ( void )
559 fParentsKnowState
= true;
560 attachToParent( getRegistryRoot(), gIOPowerPlane
);
564 //*********************************************************************************
565 // [public virtual] PMstop
567 // Immediately stop driver callouts. Schedule an async stop request to detach
569 //*********************************************************************************
571 void IOService::PMstop ( void )
573 IOPMRequest
* request
;
578 // Schedule an async PMstop request, but immediately stop any further
579 // calls to the controlling or interested drivers. This device will
580 // continue to exist in the power plane and participate in power state
581 // changes until the PMstop async request is processed.
586 PM_DEBUG("%s::PMstop() driver call busy\n", getName());
589 request
= acquirePMRequest( this, kIOPMRequestTypePMStop
);
592 PM_TRACE("[%s] %p PMstop\n", getName(), this);
593 submitPMRequest( request
);
597 //*********************************************************************************
600 // Disconnect the node from its parents and children in the Power Plane.
601 //*********************************************************************************
603 void IOService::handlePMstop ( IOPMRequest
* request
)
607 IOPowerConnection
* connection
;
608 IOService
* theChild
;
609 IOService
* theParent
;
612 PM_TRACE("[%s] %p %s start\n", getName(), this, __FUNCTION__
);
614 // remove the property
615 removeProperty(kPwrMgtKey
);
618 iter
= getParentIterator(gIOPowerPlane
);
621 while ( (next
= iter
->getNextObject()) )
623 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
625 theParent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
628 theParent
->removePowerChild(connection
);
629 theParent
->release();
636 // detach IOConnections
637 detachAbove( gIOPowerPlane
);
639 // no more power state changes
640 fParentsKnowState
= false;
643 iter
= getChildIterator(gIOPowerPlane
);
646 while ( (next
= iter
->getNextObject()) )
648 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
650 theChild
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
653 // detach nub from child
654 connection
->detachFromChild(theChild
, gIOPowerPlane
);
657 // detach us from nub
658 detachFromChild(connection
, gIOPowerPlane
);
664 // Remove all interested drivers from the list, including the power
665 // controlling driver.
667 // Usually, the controlling driver and the policy-maker functionality
668 // are implemented by the same object, and without the deregistration,
669 // the object will be holding an extra retain on itself, and cannot
672 if ( fInterestedDrivers
)
674 IOPMinformeeList
* list
= fInterestedDrivers
;
678 while ((item
= list
->firstInList()))
680 list
->removeFromList(item
->whatObject
);
685 // Tell PM_idle_timer_expiration() to ignore idle timer.
686 fIdleTimerPeriod
= 0;
689 PM_TRACE("[%s] %p %s done\n", getName(), this, __FUNCTION__
);
692 //*********************************************************************************
693 // [public virtual] addPowerChild
695 // Power Management is informing us who our children are.
696 //*********************************************************************************
698 IOReturn
IOService::addPowerChild ( IOService
* child
)
700 IOPowerConnection
* connection
= 0;
701 IOPMRequest
* requests
[3] = {0, 0, 0};
706 return kIOReturnBadArgument
;
708 if (!initialized
|| !child
->initialized
)
709 return IOPMNotYetInitialized
;
711 OUR_PMLog( kPMLogAddChild
, 0, 0 );
714 // Is this child already one of our children?
716 iter
= child
->getParentIterator( gIOPowerPlane
);
719 IORegistryEntry
* entry
;
722 while ((next
= iter
->getNextObject()))
724 if ((entry
= OSDynamicCast(IORegistryEntry
, next
)) &&
725 isChild(entry
, gIOPowerPlane
))
735 PM_DEBUG("[%s] %s (%p) is already a child\n",
736 getName(), child
->getName(), child
);
740 // Add the child to the power plane immediately, but the
741 // joining connection is marked as not ready.
742 // We want the child to appear in the power plane before
743 // returning to the caller, but don't want the caller to
744 // block on the PM work loop.
746 connection
= new IOPowerConnection
;
750 // Create a chain of PM requests to perform the bottom-half
751 // work from the PM work loop.
753 requests
[0] = acquirePMRequest(
755 /* type */ kIOPMRequestTypeAddPowerChild1
);
757 requests
[1] = acquirePMRequest(
759 /* type */ kIOPMRequestTypeAddPowerChild2
);
761 requests
[2] = acquirePMRequest(
763 /* type */ kIOPMRequestTypeAddPowerChild3
);
765 if (!requests
[0] || !requests
[1] || !requests
[2])
768 requests
[0]->setParentRequest( requests
[1] );
769 requests
[1]->setParentRequest( requests
[2] );
772 connection
->start(this);
773 connection
->setAwaitingAck(false);
774 connection
->setReadyFlag(false);
776 attachToChild( connection
, gIOPowerPlane
);
777 connection
->attachToChild( child
, gIOPowerPlane
);
779 // connection needs to be released
780 requests
[0]->fArg0
= connection
;
781 requests
[1]->fArg0
= connection
;
782 requests
[2]->fArg0
= connection
;
784 submitPMRequest( requests
, 3 );
785 return kIOReturnSuccess
;
789 if (connection
) connection
->release();
790 if (requests
[0]) releasePMRequest(requests
[0]);
791 if (requests
[1]) releasePMRequest(requests
[1]);
792 if (requests
[2]) releasePMRequest(requests
[2]);
794 // silent failure, to prevent platform drivers from adding the child
795 // to the root domain.
799 //*********************************************************************************
800 // [private] addPowerChild1
802 // Called on the power parent.
803 //*********************************************************************************
805 void IOService::addPowerChild1 ( IOPMRequest
* request
)
807 unsigned long tempDesire
= 0;
809 // Make us temporary usable before adding the child.
812 OUR_PMLog( kPMLogMakeUsable
, kPMLogMakeUsable
, fDeviceDesire
);
814 if (fControllingDriver
&& inPlane(gIOPowerPlane
) && fParentsKnowState
)
816 tempDesire
= fNumberOfPowerStates
- 1;
819 if (tempDesire
&& (fWeAreRoot
|| (fMaxCapability
>= tempDesire
)))
821 computeDesiredState( tempDesire
);
826 //*********************************************************************************
827 // [private] addPowerChild2
829 // Called on the joining child. Blocked behind addPowerChild1.
830 //*********************************************************************************
832 void IOService::addPowerChild2 ( IOPMRequest
* request
)
834 IOPowerConnection
* connection
= (IOPowerConnection
*) request
->fArg0
;
836 IOPMPowerFlags powerFlags
;
838 unsigned long powerState
;
839 unsigned long tempDesire
;
842 parent
= (IOService
*) connection
->getParentEntry(gIOPowerPlane
);
844 if (!parent
|| !inPlane(gIOPowerPlane
))
846 PM_DEBUG("[%s] addPowerChild2 not in power plane\n", getName());
850 // Parent will be waiting for us to complete this stage, safe to
851 // directly access parent's vars.
853 knowsState
= (parent
->fPowerStates
) && (parent
->fParentsKnowState
);
854 powerState
= parent
->fCurrentPowerState
;
857 powerFlags
= parent
->fPowerStates
[powerState
].outputPowerCharacter
;
861 // Set our power parent.
863 OUR_PMLog(kPMLogSetParent
, knowsState
, powerFlags
);
865 setParentInfo( powerFlags
, connection
, knowsState
);
867 connection
->setReadyFlag(true);
869 if ( fControllingDriver
&& fParentsKnowState
)
871 fMaxCapability
= fControllingDriver
->maxCapabilityForDomainState(fParentsCurrentPowerFlags
);
872 // initially change into the state we are already in
873 tempDesire
= fControllingDriver
->initialPowerStateForDomainState(fParentsCurrentPowerFlags
);
874 computeDesiredState(tempDesire
);
875 fPreviousRequest
= 0xffffffff;
880 //*********************************************************************************
881 // [private] addPowerChild3
883 // Called on the parent. Blocked behind addPowerChild2.
884 //*********************************************************************************
886 void IOService::addPowerChild3 ( IOPMRequest
* request
)
888 IOPowerConnection
* connection
= (IOPowerConnection
*) request
->fArg0
;
893 child
= (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
895 if (child
&& inPlane(gIOPowerPlane
))
897 if (child
->getProperty("IOPMStrictTreeOrder"))
899 PM_DEBUG("[%s] strict ordering enforced\n", getName());
900 fStrictTreeOrder
= true;
903 for (i
= 0; i
<= kMaxType
; i
++)
905 if ( fAggressivenessValid
[i
] )
907 child
->setAggressiveness(i
, fAggressivenessValue
[i
]);
913 PM_DEBUG("[%s] addPowerChild3 not in power plane\n", getName());
916 connection
->release();
919 //*********************************************************************************
920 // [public virtual deprecated] setPowerParent
922 // Power Management is informing us who our parent is.
923 // If we have a controlling driver, find out, given our newly-informed
924 // power domain state, what state it would be in, and then tell it
925 // to assume that state.
926 //*********************************************************************************
928 IOReturn
IOService::setPowerParent (
929 IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags powerFlags
)
931 return kIOReturnUnsupported
;
934 //*********************************************************************************
935 // [public virtual] removePowerChild
937 // Called on a parent whose child is being removed by PMstop().
938 //*********************************************************************************
940 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theNub
)
942 IORegistryEntry
* theChild
;
945 OUR_PMLog( kPMLogRemoveChild
, 0, 0 );
949 // detach nub from child
950 theChild
= theNub
->copyChildEntry(gIOPowerPlane
);
953 theNub
->detachFromChild(theChild
, gIOPowerPlane
);
956 // detach from the nub
957 detachFromChild(theNub
, gIOPowerPlane
);
959 // Are we awaiting an ack from this child?
960 if ( theNub
->getAwaitingAck() )
962 // yes, pretend we got one
963 theNub
->setAwaitingAck(false);
964 if (fHeadNotePendingAcks
!= 0 )
966 // that's one fewer ack to worry about
967 fHeadNotePendingAcks
--;
970 if ( fHeadNotePendingAcks
== 0 )
979 // Schedule a request to re-scan child desires and clamp bits.
980 if (!fWillAdjustPowerState
)
982 IOPMRequest
* request
;
984 request
= acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState
);
987 submitPMRequest( request
);
988 fWillAdjustPowerState
= true;
995 //*********************************************************************************
996 // [public virtual] registerPowerDriver
998 // A driver has called us volunteering to control power to our device.
999 //*********************************************************************************
1001 IOReturn
IOService::registerPowerDriver (
1002 IOService
* powerDriver
,
1003 IOPMPowerState
* powerStates
,
1004 unsigned long numberOfStates
)
1006 IOPMRequest
* request
;
1007 IOPMPowerState
* powerStatesCopy
= 0;
1010 return IOPMNotYetInitialized
;
1012 // Validate arguments.
1013 if (!powerStates
|| (numberOfStates
< 2))
1015 OUR_PMLog(kPMLogControllingDriverErr5
, numberOfStates
, 0);
1016 return kIOReturnBadArgument
;
1021 OUR_PMLog(kPMLogControllingDriverErr4
, 0, 0);
1022 return kIOReturnBadArgument
;
1025 if (powerStates
[0].version
!= kIOPMPowerStateVersion1
)
1027 OUR_PMLog(kPMLogControllingDriverErr1
, powerStates
[0].version
, 0);
1028 return kIOReturnBadArgument
;
1032 // Make a copy of the supplied power state array.
1033 powerStatesCopy
= IONew(IOPMPowerState
, numberOfStates
);
1034 if (!powerStatesCopy
)
1037 bcopy( powerStates
, powerStatesCopy
,
1038 sizeof(IOPMPowerState
) * numberOfStates
);
1040 request
= acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver
);
1044 powerDriver
->retain();
1045 request
->fArg0
= (void *) powerDriver
;
1046 request
->fArg1
= (void *) powerStatesCopy
;
1047 request
->fArg2
= (void *) numberOfStates
;
1049 submitPMRequest( request
);
1050 return kIOReturnSuccess
;
1054 if (powerStatesCopy
)
1055 IODelete(powerStatesCopy
, IOPMPowerState
, numberOfStates
);
1056 return kIOReturnNoMemory
;
1059 //*********************************************************************************
1060 // [private] handleRegisterPowerDriver
1061 //*********************************************************************************
1063 void IOService::handleRegisterPowerDriver ( IOPMRequest
* request
)
1065 IOService
* powerDriver
= (IOService
*) request
->fArg0
;
1066 IOPMPowerState
* powerStates
= (IOPMPowerState
*) request
->fArg1
;
1067 unsigned long numberOfStates
= (unsigned long) request
->fArg2
;
1071 PM_ASSERT_IN_GATE();
1072 assert(powerStates
);
1073 assert(powerDriver
);
1074 assert(numberOfStates
> 1);
1076 if ( !fNumberOfPowerStates
)
1078 OUR_PMLog(kPMLogControllingDriver
,
1079 (unsigned long) numberOfStates
,
1080 (unsigned long) powerStates
[0].version
);
1082 fPowerStates
= powerStates
;
1083 fNumberOfPowerStates
= numberOfStates
;
1084 fControllingDriver
= powerDriver
;
1085 fCurrentCapabilityFlags
= fPowerStates
[0].capabilityFlags
;
1087 // make a mask of all the character bits we know about
1088 fOutputPowerCharacterFlags
= 0;
1089 for ( i
= 0; i
< numberOfStates
; i
++ ) {
1090 fOutputPowerCharacterFlags
|= fPowerStates
[i
].outputPowerCharacter
;
1093 // Register powerDriver as interested, unless already done.
1094 // We don't want to register the default implementation since
1095 // it does nothing. One ramification of not always registering
1096 // is the one fewer retain count held.
1098 root
= getPlatform()->getProvider();
1101 ((OSMemberFunctionCast(void (*)(void),
1102 root
, &IOService::powerStateDidChangeTo
)) !=
1103 ((OSMemberFunctionCast(void (*)(void),
1104 this, &IOService::powerStateDidChangeTo
)))) ||
1105 ((OSMemberFunctionCast(void (*)(void),
1106 root
, &IOService::powerStateWillChangeTo
)) !=
1107 ((OSMemberFunctionCast(void (*)(void),
1108 this, &IOService::powerStateWillChangeTo
)))))
1110 if (fInterestedDrivers
->findItem(powerDriver
) == NULL
)
1113 fInterestedDrivers
->appendNewInformee(powerDriver
);
1118 if ( fNeedToBecomeUsable
) {
1119 fNeedToBecomeUsable
= false;
1120 fDeviceDesire
= fNumberOfPowerStates
- 1;
1123 if ( inPlane(gIOPowerPlane
) && fParentsKnowState
)
1125 unsigned long tempDesire
;
1126 fMaxCapability
= fControllingDriver
->maxCapabilityForDomainState(fParentsCurrentPowerFlags
);
1127 // initially change into the state we are already in
1128 tempDesire
= fControllingDriver
->initialPowerStateForDomainState(fParentsCurrentPowerFlags
);
1129 computeDesiredState(tempDesire
);
1135 OUR_PMLog(kPMLogControllingDriverErr2
, numberOfStates
, 0);
1136 IODelete(powerStates
, IOPMPowerState
, numberOfStates
);
1139 powerDriver
->release();
1142 //*********************************************************************************
1143 // [public virtual] registerInterestedDriver
1145 // Add the caller to our list of interested drivers and return our current
1146 // power state. If we don't have a power-controlling driver yet, we will
1147 // call this interested driver again later when we do get a driver and find
1148 // out what the current power state of the device is.
1149 //*********************************************************************************
1151 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* driver
)
1153 IOPMRequest
* request
;
1156 if (!initialized
|| !fInterestedDrivers
)
1157 return IOPMNotPowerManaged
;
1160 signal
= (!fInsertInterestSet
&& !fRemoveInterestSet
);
1161 if (fInsertInterestSet
== NULL
)
1162 fInsertInterestSet
= OSSet::withCapacity(4);
1163 if (fInsertInterestSet
)
1164 fInsertInterestSet
->setObject(driver
);
1169 request
= acquirePMRequest( this, kIOPMRequestTypeInterestChanged
);
1171 submitPMRequest( request
);
1174 // This return value cannot be trusted, but return a value
1175 // for those clients that care.
1177 OUR_PMLog(kPMLogInterestedDriver
, kIOPMDeviceUsable
, 2);
1178 return kIOPMDeviceUsable
;
1181 //*********************************************************************************
1182 // [public virtual] deRegisterInterestedDriver
1183 //*********************************************************************************
1185 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* driver
)
1187 IOPMinformeeList
* list
;
1188 IOPMinformee
* item
;
1189 IOPMRequest
* request
;
1192 if (!initialized
|| !fInterestedDrivers
)
1193 return IOPMNotPowerManaged
;
1196 signal
= (!fRemoveInterestSet
&& !fInsertInterestSet
);
1197 if (fRemoveInterestSet
== NULL
)
1198 fRemoveInterestSet
= OSSet::withCapacity(4);
1199 if (fRemoveInterestSet
)
1201 fRemoveInterestSet
->setObject(driver
);
1203 list
= fInterestedDrivers
;
1204 item
= list
->findItem(driver
);
1205 if (item
&& item
->active
)
1207 item
->active
= false;
1209 if (fDriverCallBusy
)
1210 PM_DEBUG("%s::deRegisterInterestedDriver() driver call busy\n", getName());
1216 request
= acquirePMRequest( this, kIOPMRequestTypeInterestChanged
);
1218 submitPMRequest( request
);
1224 //*********************************************************************************
1225 // [private] handleInterestChanged
1227 // Handle interest added or removed.
1228 //*********************************************************************************
1230 void IOService::handleInterestChanged( IOPMRequest
* request
)
1233 IOPMinformee
* informee
;
1234 IOPMinformeeList
* list
= fInterestedDrivers
;
1238 if (fInsertInterestSet
)
1240 while ((driver
= (IOService
*) fInsertInterestSet
->getAnyObject()))
1242 if ((list
->findItem(driver
) == NULL
) &&
1243 (!fRemoveInterestSet
||
1244 !fRemoveInterestSet
->containsObject(driver
)))
1246 informee
= list
->appendNewInformee(driver
);
1248 fInsertInterestSet
->removeObject(driver
);
1250 fInsertInterestSet
->release();
1251 fInsertInterestSet
= 0;
1254 if (fRemoveInterestSet
)
1256 while ((driver
= (IOService
*) fRemoveInterestSet
->getAnyObject()))
1258 informee
= list
->findItem(driver
);
1261 if (fHeadNotePendingAcks
&& informee
->timer
)
1263 informee
->timer
= 0;
1264 fHeadNotePendingAcks
--;
1266 list
->removeFromList(driver
);
1268 fRemoveInterestSet
->removeObject(driver
);
1270 fRemoveInterestSet
->release();
1271 fRemoveInterestSet
= 0;
1277 //*********************************************************************************
1278 // [public virtual] acknowledgePowerChange
1280 // After we notified one of the interested drivers or a power-domain child
1281 // of an impending change in power, it has called to say it is now
1282 // prepared for the change. If this object is the last to
1283 // acknowledge this change, we take whatever action we have been waiting
1285 // That may include acknowledging to our parent. In this case, we do it
1286 // last of all to insure that this doesn't cause the parent to call us some-
1287 // where else and alter data we are relying on here (like the very existance
1288 // of a "current change note".)
1289 //*********************************************************************************
1291 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
1293 IOPMRequest
* request
;
1296 return IOPMNotYetInitialized
;
1298 return kIOReturnBadArgument
;
1300 request
= acquirePMRequest( this, kIOPMRequestTypeAckPowerChange
);
1303 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__
);
1304 return kIOReturnNoMemory
;
1307 whichObject
->retain();
1308 request
->fArg0
= whichObject
;
1310 submitPMRequest( request
);
1314 //*********************************************************************************
1315 // [private] handleAcknowledgePowerChange
1316 //*********************************************************************************
1318 bool IOService::handleAcknowledgePowerChange ( IOPMRequest
* request
)
1320 IOPMinformee
* informee
;
1321 unsigned long childPower
= kIOPMUnknown
;
1322 IOService
* theChild
;
1323 IOService
* whichObject
;
1324 bool all_acked
= false;
1326 PM_ASSERT_IN_GATE();
1327 whichObject
= (IOService
*) request
->fArg0
;
1328 assert(whichObject
);
1330 // one of our interested drivers?
1331 informee
= fInterestedDrivers
->findItem( whichObject
);
1332 if ( informee
== NULL
)
1334 if ( !isChild(whichObject
, gIOPowerPlane
) )
1336 OUR_PMLog(kPMLogAcknowledgeErr1
, 0, 0);
1339 OUR_PMLog(kPMLogChildAcknowledge
, fHeadNotePendingAcks
, 0);
1342 OUR_PMLog(kPMLogDriverAcknowledge
, fHeadNotePendingAcks
, 0);
1345 if ( fHeadNotePendingAcks
!= 0 )
1347 assert(fPowerStates
!= NULL
);
1349 // yes, make sure we're expecting acks
1350 if ( informee
!= NULL
)
1352 // it's an interested driver
1353 // make sure we're expecting this ack
1354 if ( informee
->timer
!= 0 )
1356 #if LOG_SETPOWER_TIMES
1357 if (informee
->timer
> 0)
1359 uint64_t nsec
= computeTimeDeltaNS(&informee
->startTime
);
1360 if (nsec
> LOG_SETPOWER_TIMES
)
1361 PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
1362 informee
->whatObject
->getName(),
1363 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
1364 informee
->whatObject
,
1365 fName
, fCurrentPowerState
, fHeadNoteState
, NS_TO_MS(nsec
));
1369 informee
->timer
= 0;
1370 // that's one fewer to worry about
1371 fHeadNotePendingAcks
--;
1373 // this driver has already acked
1374 OUR_PMLog(kPMLogAcknowledgeErr2
, 0, 0);
1378 // make sure we're expecting this ack
1379 if ( ((IOPowerConnection
*)whichObject
)->getAwaitingAck() )
1381 // that's one fewer to worry about
1382 fHeadNotePendingAcks
--;
1383 ((IOPowerConnection
*)whichObject
)->setAwaitingAck(false);
1384 theChild
= (IOService
*)whichObject
->copyChildEntry(gIOPowerPlane
);
1387 childPower
= theChild
->currentPowerConsumption();
1388 theChild
->release();
1390 if ( childPower
== kIOPMUnknown
)
1392 fPowerStates
[fHeadNoteState
].staticPower
= kIOPMUnknown
;
1394 if ( fPowerStates
[fHeadNoteState
].staticPower
!= kIOPMUnknown
)
1396 fPowerStates
[fHeadNoteState
].staticPower
+= childPower
;
1402 if ( fHeadNotePendingAcks
== 0 ) {
1403 // yes, stop the timer
1405 // and now we can continue
1409 OUR_PMLog(kPMLogAcknowledgeErr3
, 0, 0); // not expecting anybody to ack
1414 whichObject
->release();
1419 //*********************************************************************************
1420 // [public virtual] acknowledgeSetPowerState
1422 // After we instructed our controlling driver to change power states,
1423 // it has called to say it has finished doing so.
1424 // We continue to process the power state change.
1425 //*********************************************************************************
1427 IOReturn
IOService::acknowledgeSetPowerState ( void )
1429 IOPMRequest
* request
;
1432 return IOPMNotYetInitialized
;
1434 request
= acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState
);
1437 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__
);
1438 return kIOReturnNoMemory
;
1441 submitPMRequest( request
);
1442 return kIOReturnSuccess
;
1445 //*********************************************************************************
1446 // [private] adjustPowerState
1448 // Child has signaled a change - child changed it's desire, new child added,
1449 // existing child removed. Adjust our power state accordingly.
1450 //*********************************************************************************
1452 void IOService::adjustPowerState( void )
1454 PM_ASSERT_IN_GATE();
1455 if (inPlane(gIOPowerPlane
))
1457 rebuildChildClampBits();
1458 computeDesiredState();
1459 if ( fControllingDriver
&& fParentsKnowState
)
1464 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__
);
1467 fWillAdjustPowerState
= false;
1470 //*********************************************************************************
1471 // [public deprecated] powerDomainWillChangeTo
1473 // Called by the power-hierarchy parent notifying of a new power state
1474 // in the power domain.
1475 // We enqueue a parent power-change to our queue of power changes.
1476 // This may or may not cause us to change power, depending on what
1477 // kind of change is occuring in the domain.
1478 //*********************************************************************************
1480 IOReturn
IOService::powerDomainWillChangeTo (
1481 IOPMPowerFlags newPowerFlags
,
1482 IOPowerConnection
* whichParent
)
1485 return kIOReturnUnsupported
;
1488 //*********************************************************************************
1489 // [private] handlePowerDomainWillChangeTo
1490 //*********************************************************************************
1492 void IOService::handlePowerDomainWillChangeTo ( IOPMRequest
* request
)
1494 IOPMPowerFlags newPowerFlags
= (IOPMPowerFlags
) request
->fArg0
;
1495 IOPowerConnection
* whichParent
= (IOPowerConnection
*) request
->fArg1
;
1496 bool powerWillDrop
= (bool) request
->fArg2
;
1499 IOPowerConnection
* connection
;
1500 unsigned long newPowerState
;
1501 IOPMPowerFlags combinedPowerFlags
;
1502 bool savedParentsKnowState
;
1503 IOReturn result
= IOPMAckImplied
;
1505 PM_ASSERT_IN_GATE();
1506 OUR_PMLog(kPMLogWillChange
, newPowerFlags
, 0);
1508 if (!inPlane(gIOPowerPlane
) || !whichParent
|| !whichParent
->getAwaitingAck())
1510 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__
);
1514 savedParentsKnowState
= fParentsKnowState
;
1516 // Combine parents' power flags to determine our maximum state
1517 // within the new power domain
1518 combinedPowerFlags
= 0;
1520 iter
= getParentIterator(gIOPowerPlane
);
1523 while ( (next
= iter
->getNextObject()) )
1525 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
1527 if ( connection
== whichParent
)
1528 combinedPowerFlags
|= newPowerFlags
;
1530 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
1536 if ( fControllingDriver
)
1538 newPowerState
= fControllingDriver
->maxCapabilityForDomainState(
1539 combinedPowerFlags
);
1541 result
= enqueuePowerChange(
1542 /* flags */ IOPMParentInitiated
| IOPMDomainWillChange
,
1543 /* power state */ newPowerState
,
1544 /* domain state */ combinedPowerFlags
,
1545 /* connection */ whichParent
,
1546 /* parent state */ newPowerFlags
);
1549 // If parent is dropping power, immediately update the parent's
1550 // capability flags. Any future merging of parent(s) combined
1551 // power flags should account for this power drop.
1555 setParentInfo(newPowerFlags
, whichParent
, true);
1558 // Parent is expecting an ACK from us. If we did not embark on a state
1559 // transition, when enqueuePowerChang() returns IOPMAckImplied. We are
1560 // still required to issue an ACK to our parent.
1562 if (IOPMAckImplied
== result
)
1565 parent
= (IOService
*) whichParent
->copyParentEntry(gIOPowerPlane
);
1569 parent
->acknowledgePowerChange( whichParent
);
1574 // If the parent registers it's power driver late, then this is the
1575 // first opportunity to tell our parent about our desire.
1577 if (!savedParentsKnowState
&& fParentsKnowState
)
1579 PM_TRACE("[%s] powerDomainWillChangeTo: parentsKnowState = true\n",
1581 ask_parent( fDesiredPowerState
);
1585 // Drop the retain from notifyChild().
1586 if (whichParent
) whichParent
->release();
1589 //*********************************************************************************
1590 // [public deprecated] powerDomainDidChangeTo
1592 // Called by the power-hierarchy parent after the power state of the power domain
1593 // has settled at a new level.
1594 // We enqueue a parent power-change to our queue of power changes.
1595 // This may or may not cause us to change power, depending on what
1596 // kind of change is occuring in the domain.
1597 //*********************************************************************************
1599 IOReturn
IOService::powerDomainDidChangeTo (
1600 IOPMPowerFlags newPowerFlags
,
1601 IOPowerConnection
* whichParent
)
1604 return kIOReturnUnsupported
;
1607 //*********************************************************************************
1608 // [private] handlePowerDomainDidChangeTo
1609 //*********************************************************************************
1611 void IOService::handlePowerDomainDidChangeTo ( IOPMRequest
* request
)
1613 IOPMPowerFlags newPowerFlags
= (IOPMPowerFlags
) request
->fArg0
;
1614 IOPowerConnection
* whichParent
= (IOPowerConnection
*) request
->fArg1
;
1615 unsigned long newPowerState
;
1616 bool savedParentsKnowState
;
1617 IOReturn result
= IOPMAckImplied
;
1619 PM_ASSERT_IN_GATE();
1620 OUR_PMLog(kPMLogDidChange
, newPowerFlags
, 0);
1622 if (!inPlane(gIOPowerPlane
) || !whichParent
|| !whichParent
->getAwaitingAck())
1624 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__
);
1628 savedParentsKnowState
= fParentsKnowState
;
1630 setParentInfo(newPowerFlags
, whichParent
, true);
1632 if ( fControllingDriver
)
1634 newPowerState
= fControllingDriver
->maxCapabilityForDomainState(
1635 fParentsCurrentPowerFlags
);
1637 result
= enqueuePowerChange(
1638 /* flags */ IOPMParentInitiated
| IOPMDomainDidChange
,
1639 /* power state */ newPowerState
,
1640 /* domain state */ fParentsCurrentPowerFlags
,
1641 /* connection */ whichParent
,
1642 /* parent state */ 0);
1645 // Parent is expecting an ACK from us. If we did not embark on a state
1646 // transition, when enqueuePowerChang() returns IOPMAckImplied. We are
1647 // still required to issue an ACK to our parent.
1649 if (IOPMAckImplied
== result
)
1652 parent
= (IOService
*) whichParent
->copyParentEntry(gIOPowerPlane
);
1656 parent
->acknowledgePowerChange( whichParent
);
1661 // If the parent registers it's power driver late, then this is the
1662 // first opportunity to tell our parent about our desire.
1664 if (!savedParentsKnowState
&& fParentsKnowState
)
1666 PM_TRACE("[%s] powerDomainDidChangeTo: parentsKnowState = true\n",
1668 ask_parent( fDesiredPowerState
);
1672 // Drop the retain from notifyChild().
1673 if (whichParent
) whichParent
->release();
1676 //*********************************************************************************
1677 // [private] setParentInfo
1679 // Set our connection data for one specific parent, and then combine all the parent
1681 //*********************************************************************************
1683 void IOService::setParentInfo (
1684 IOPMPowerFlags newPowerFlags
,
1685 IOPowerConnection
* whichParent
,
1690 IOPowerConnection
* conn
;
1692 PM_ASSERT_IN_GATE();
1694 // set our connection data
1695 whichParent
->setParentCurrentPowerFlags(newPowerFlags
);
1696 whichParent
->setParentKnowsState(knowsState
);
1698 // recompute our parent info
1699 fParentsCurrentPowerFlags
= 0;
1700 fParentsKnowState
= true;
1702 iter
= getParentIterator(gIOPowerPlane
);
1705 while ( (next
= iter
->getNextObject()) )
1707 if ( (conn
= OSDynamicCast(IOPowerConnection
, next
)) )
1709 fParentsKnowState
&= conn
->parentKnowsState();
1710 fParentsCurrentPowerFlags
|= conn
->parentCurrentPowerFlags();
1717 //*********************************************************************************
1718 // [private] rebuildChildClampBits
1720 // The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1721 // indicate that one of our children (or grandchildren or great-grandchildren ...)
1722 // doesn't support idle or system sleep in its current state. Since we don't track
1723 // the origin of each bit, every time any child changes state we have to clear
1724 // these bits and rebuild them.
1725 //*********************************************************************************
1727 void IOService::rebuildChildClampBits ( void )
1732 IOPowerConnection
* connection
;
1733 unsigned long powerState
;
1735 // A child's desires has changed. We need to rebuild the child-clamp bits in
1736 // our power state array. Start by clearing the bits in each power state.
1738 for ( i
= 0; i
< fNumberOfPowerStates
; i
++ )
1740 fPowerStates
[i
].capabilityFlags
&= ~(kIOPMChildClamp
| kIOPMChildClamp2
);
1743 // Loop through the children. When we encounter the calling child, save the
1744 // computed state as this child's desire. And set the ChildClamp bits in any
1745 // of our states that some child has clamp on.
1747 iter
= getChildIterator(gIOPowerPlane
);
1750 while ( (next
= iter
->getNextObject()) )
1752 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
1754 if (connection
->getReadyFlag() == false)
1756 PM_CONNECT("[%s] %s: connection not ready\n",
1757 getName(), __FUNCTION__
);
1761 powerState
= connection
->getDesiredDomainState();
1762 if (powerState
< fNumberOfPowerStates
)
1764 if ( connection
->getPreventIdleSleepFlag() )
1765 fPowerStates
[powerState
].capabilityFlags
|= kIOPMChildClamp
;
1766 if ( connection
->getPreventSystemSleepFlag() )
1767 fPowerStates
[powerState
].capabilityFlags
|= kIOPMChildClamp2
;
1775 //*********************************************************************************
1776 // [public virtual] requestPowerDomainState
1778 // The child of a power domain calls it parent here to request power of a certain
1780 //*********************************************************************************
1782 IOReturn
IOService::requestPowerDomainState (
1783 IOPMPowerFlags desiredState
,
1784 IOPowerConnection
* whichChild
,
1785 unsigned long specification
)
1788 unsigned long computedState
;
1789 unsigned long theDesiredState
;
1791 IOPMRequest
* childRequest
;
1794 return IOPMNotYetInitialized
;
1796 if (gIOPMWorkLoop
->onThread() == false)
1798 PM_DEBUG("[%s] called requestPowerDomainState\n", getName());
1799 return kIOReturnSuccess
;
1802 theDesiredState
= desiredState
& ~(kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
1804 OUR_PMLog(kPMLogRequestDomain
, desiredState
, specification
);
1806 if (!isChild(whichChild
, gIOPowerPlane
))
1807 return kIOReturnNotAttached
;
1809 if (fControllingDriver
== NULL
|| !fPowerStates
)
1810 return IOPMNotYetInitialized
;
1812 child
= (IOService
*) whichChild
->getChildEntry(gIOPowerPlane
);
1815 switch (specification
) {
1816 case IOPMLowestState
:
1818 while ( i
< fNumberOfPowerStates
)
1820 if ( ( fPowerStates
[i
].outputPowerCharacter
& theDesiredState
) ==
1821 (theDesiredState
& fOutputPowerCharacterFlags
) )
1827 if ( i
>= fNumberOfPowerStates
)
1829 return IOPMNoSuchState
;
1833 case IOPMNextLowerState
:
1834 i
= fCurrentPowerState
- 1;
1835 while ( (int) i
>= 0 )
1837 if ( ( fPowerStates
[i
].outputPowerCharacter
& theDesiredState
) ==
1838 (theDesiredState
& fOutputPowerCharacterFlags
) )
1846 return IOPMNoSuchState
;
1850 case IOPMHighestState
:
1851 i
= fNumberOfPowerStates
;
1852 while ( (int) i
>= 0 )
1855 if ( ( fPowerStates
[i
].outputPowerCharacter
& theDesiredState
) ==
1856 (theDesiredState
& fOutputPowerCharacterFlags
) )
1863 return IOPMNoSuchState
;
1867 case IOPMNextHigherState
:
1868 i
= fCurrentPowerState
+ 1;
1869 while ( i
< fNumberOfPowerStates
)
1871 if ( ( fPowerStates
[i
].outputPowerCharacter
& theDesiredState
) ==
1872 (theDesiredState
& fOutputPowerCharacterFlags
) )
1878 if ( i
== fNumberOfPowerStates
)
1880 return IOPMNoSuchState
;
1885 return IOPMBadSpecification
;
1890 // Clamp removed on the initial power request from a new child.
1892 if (fClampOn
&& !whichChild
->childHasRequestedPower())
1894 PM_TRACE("[%s] %p power clamp removed (child = %p)\n",
1895 getName(), this, whichChild
);
1900 // Record the child's desires on the connection.
1901 #if SUPPORT_IDLE_CANCEL
1902 bool attemptCancel
= ((kIOPMPreventIdleSleep
& desiredState
) && !whichChild
->getPreventIdleSleepFlag());
1904 whichChild
->setDesiredDomainState( computedState
);
1905 whichChild
->setPreventIdleSleepFlag( desiredState
& kIOPMPreventIdleSleep
);
1906 whichChild
->setPreventSystemSleepFlag( desiredState
& kIOPMPreventSystemSleep
);
1907 whichChild
->setChildHasRequestedPower();
1909 if (whichChild
->getReadyFlag() == false)
1912 // Issue a ping for us to re-evaluate all children desires and
1913 // possibly change power state.
1915 if (!fWillAdjustPowerState
&& !fDeviceOverrides
)
1917 childRequest
= acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState
);
1920 submitPMRequest( childRequest
);
1921 fWillAdjustPowerState
= true;
1924 #if SUPPORT_IDLE_CANCEL
1927 childRequest
= acquirePMRequest( this, kIOPMRequestTypeIdleCancel
);
1930 submitPMRequest( childRequest
);
1938 //*********************************************************************************
1939 // [public virtual] temporaryPowerClampOn
1941 // A power domain wants to clamp its power on till it has children which
1942 // will thendetermine the power domain state.
1944 // We enter the highest state until addPowerChild is called.
1945 //*********************************************************************************
1947 IOReturn
IOService::temporaryPowerClampOn ( void )
1949 IOPMRequest
* request
;
1952 return IOPMNotYetInitialized
;
1954 request
= acquirePMRequest( this, kIOPMRequestTypeTemporaryPowerClamp
);
1956 return kIOReturnNoMemory
;
1958 submitPMRequest( request
);
1962 //*********************************************************************************
1963 // [public virtual] makeUsable
1965 // Some client of our device is asking that we become usable. Although
1966 // this has not come from a subclassed device object, treat it exactly
1967 // as if it had. In this way, subsequent requests for lower power from
1968 // a subclassed device object will pre-empt this request.
1970 // We treat this as a subclass object request to switch to the
1971 // highest power state.
1972 //*********************************************************************************
1974 IOReturn
IOService::makeUsable ( void )
1976 IOPMRequest
* request
;
1979 return IOPMNotYetInitialized
;
1981 OUR_PMLog(kPMLogMakeUsable
, 0, 0);
1983 request
= acquirePMRequest( this, kIOPMRequestTypeMakeUsable
);
1985 return kIOReturnNoMemory
;
1987 submitPMRequest( request
);
1991 //*********************************************************************************
1992 // [private] handleMakeUsable
1994 // Handle a request to become usable.
1995 //*********************************************************************************
1997 void IOService::handleMakeUsable ( IOPMRequest
* request
)
1999 PM_ASSERT_IN_GATE();
2000 if ( fControllingDriver
)
2002 fDeviceDesire
= fNumberOfPowerStates
- 1;
2003 computeDesiredState();
2004 if ( inPlane(gIOPowerPlane
) && fParentsKnowState
)
2011 fNeedToBecomeUsable
= true;
2015 //*********************************************************************************
2016 // [public virtual] currentCapability
2017 //*********************************************************************************
2019 IOPMPowerFlags
IOService::currentCapability ( void )
2022 return IOPMNotPowerManaged
;
2024 return fCurrentCapabilityFlags
;
2027 //*********************************************************************************
2028 // [public virtual] changePowerStateTo
2030 // For some reason, our power-controlling driver has decided it needs to change
2031 // power state. We enqueue the power change so that appropriate parties
2032 // will be notified, and then we will instruct the driver to make the change.
2033 //*********************************************************************************
2035 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
2037 IOPMRequest
* request
;
2040 return IOPMNotYetInitialized
;
2042 OUR_PMLog(kPMLogChangeStateTo
, ordinal
, 0);
2044 request
= acquirePMRequest( this, kIOPMRequestTypeChangePowerStateTo
);
2046 return kIOReturnNoMemory
;
2048 request
->fArg0
= (void *) ordinal
;
2049 request
->fArg1
= (void *) false;
2051 // Avoid needless downwards power transitions by clamping power in
2052 // computeDesiredState() until the delayed request is processed.
2054 if (gIOPMWorkLoop
->inGate())
2056 fTempClampPowerState
= max(fTempClampPowerState
, ordinal
);
2058 request
->fArg1
= (void *) true;
2061 submitPMRequest( request
);
2065 //*********************************************************************************
2066 // [private] handleChangePowerStateTo
2067 //*********************************************************************************
2069 void IOService::handleChangePowerStateTo ( IOPMRequest
* request
)
2071 unsigned long ordinal
= (unsigned long) request
->fArg0
;
2073 PM_ASSERT_IN_GATE();
2076 assert(fTempClampCount
!= 0);
2077 if (fTempClampCount
)
2079 if (!fTempClampCount
)
2080 fTempClampPowerState
= 0;
2083 if ( fControllingDriver
&& (ordinal
< fNumberOfPowerStates
))
2085 fDriverDesire
= ordinal
;
2086 computeDesiredState();
2087 if ( inPlane(gIOPowerPlane
) && fParentsKnowState
)
2094 //*********************************************************************************
2095 // [public virtual] changePowerStateToPriv
2097 // For some reason, a subclassed device object has decided it needs to change
2098 // power state. We enqueue the power change so that appropriate parties
2099 // will be notified, and then we will instruct the driver to make the change.
2100 //*********************************************************************************
2102 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
2104 IOPMRequest
* request
;
2107 return IOPMNotYetInitialized
;
2109 request
= acquirePMRequest( this, kIOPMRequestTypeChangePowerStateToPriv
);
2111 return kIOReturnNoMemory
;
2113 request
->fArg0
= (void *) ordinal
;
2114 request
->fArg1
= (void *) false;
2116 // Avoid needless downwards power transitions by clamping power in
2117 // computeDesiredState() until the delayed request is processed.
2119 if (gIOPMWorkLoop
->inGate())
2121 fTempClampPowerState
= max(fTempClampPowerState
, ordinal
);
2123 request
->fArg1
= (void *) true;
2126 submitPMRequest( request
);
2130 //*********************************************************************************
2131 // [private] handleChangePowerStateToPriv
2132 //*********************************************************************************
2134 void IOService::handleChangePowerStateToPriv ( IOPMRequest
* request
)
2136 unsigned long ordinal
= (unsigned long) request
->fArg0
;
2138 PM_ASSERT_IN_GATE();
2139 OUR_PMLog(kPMLogChangeStateToPriv
, ordinal
, 0);
2142 assert(fTempClampCount
!= 0);
2143 if (fTempClampCount
)
2145 if (!fTempClampCount
)
2146 fTempClampPowerState
= 0;
2149 if ( fControllingDriver
&& (ordinal
< fNumberOfPowerStates
))
2151 fDeviceDesire
= ordinal
;
2152 computeDesiredState();
2153 if ( inPlane(gIOPowerPlane
) && fParentsKnowState
)
2160 //*********************************************************************************
2161 // [private] computeDesiredState
2162 //*********************************************************************************
2164 void IOService::computeDesiredState ( unsigned long tempDesire
)
2168 IOPowerConnection
* connection
;
2169 unsigned long newDesiredState
= 0;
2170 unsigned long childDesire
= 0;
2171 unsigned long deviceDesire
;
2174 deviceDesire
= tempDesire
;
2176 deviceDesire
= fDeviceDesire
;
2178 // If clamp is on, always override deviceDesire to max.
2180 if (fClampOn
&& fNumberOfPowerStates
)
2181 deviceDesire
= fNumberOfPowerStates
- 1;
2183 // Compute the maximum of our children's desires,
2184 // our controlling driver's desire, and the subclass device's desire.
2186 if ( !fDeviceOverrides
)
2188 iter
= getChildIterator(gIOPowerPlane
);
2191 while ( (next
= iter
->getNextObject()) )
2193 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
2195 if (connection
->getReadyFlag() == false)
2197 PM_CONNECT("[%s] %s: connection not ready\n",
2198 getName(), __FUNCTION__
);
2202 if (connection
->getDesiredDomainState() > childDesire
)
2203 childDesire
= connection
->getDesiredDomainState();
2209 fChildrenDesire
= childDesire
;
2210 newDesiredState
= max(childDesire
, fDriverDesire
);
2213 newDesiredState
= max(deviceDesire
, newDesiredState
);
2214 if (fTempClampCount
&& (fTempClampPowerState
< fNumberOfPowerStates
))
2215 newDesiredState
= max(fTempClampPowerState
, newDesiredState
);
2217 fDesiredPowerState
= newDesiredState
;
2219 // Limit check against number of power states.
2221 if (fNumberOfPowerStates
== 0)
2222 fDesiredPowerState
= 0;
2223 else if (fDesiredPowerState
>= fNumberOfPowerStates
)
2224 fDesiredPowerState
= fNumberOfPowerStates
- 1;
2226 // Restart idle timer if stopped and deviceDesire has increased.
2228 if (fDeviceDesire
&& fActivityTimerStopped
)
2230 fActivityTimerStopped
= false;
2231 start_PM_idle_timer();
2234 // Invalidate cached tickle power state when desires change, and not
2235 // due to a tickle request. This invalidation must occur before the
2236 // power state change to minimize races. We want to err on the side
2237 // of servicing more activity tickles rather than dropping one when
2238 // the device is in a low power state.
2240 if (fPMRequest
&& (fPMRequest
->getType() != kIOPMRequestTypeActivityTickle
) &&
2241 (fActivityTicklePowerState
!= -1))
2243 IOLockLock(fActivityLock
);
2244 fActivityTicklePowerState
= -1;
2245 IOLockUnlock(fActivityLock
);
2248 PM_TRACE(" NewState %ld, Child %ld, Driver %ld, Device %ld, Clamp %d (%ld)\n",
2249 fDesiredPowerState
, childDesire
, fDriverDesire
, deviceDesire
,
2250 fClampOn
, fTempClampCount
? fTempClampPowerState
: 0);
2253 //*********************************************************************************
2254 // [private] changeState
2256 // A subclass object, our controlling driver, or a power domain child
2257 // has asked for a different power state. Here we compute what new
2258 // state we should enter and enqueue the change (or start it).
2259 //*********************************************************************************
2261 IOReturn
IOService::changeState ( void )
2265 PM_ASSERT_IN_GATE();
2266 assert(inPlane(gIOPowerPlane
));
2267 assert(fParentsKnowState
);
2268 assert(fControllingDriver
);
2270 result
= enqueuePowerChange(
2271 /* flags */ IOPMWeInitiated
,
2272 /* power state */ fDesiredPowerState
,
2273 /* domain state */ 0,
2275 /* parent state */ 0);
2280 //*********************************************************************************
2281 // [public virtual] currentPowerConsumption
2283 //*********************************************************************************
2285 unsigned long IOService::currentPowerConsumption ( void )
2288 return kIOPMUnknown
;
2290 return fCurrentPowerConsumption
;
2293 //*********************************************************************************
2294 // [public virtual] getPMworkloop
2295 //*********************************************************************************
2297 IOWorkLoop
* IOService::getPMworkloop ( void )
2299 return gIOPMWorkLoop
;
2302 //*********************************************************************************
2303 // [public virtual] activityTickle
2305 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
2306 // flag to be set, and the device state checked. If the device has been
2307 // powered down, it is powered up again.
2308 // The tickle with parameter kIOPMSubclassPolicy is ignored here and
2309 // should be intercepted by a subclass.
2310 //*********************************************************************************
2312 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
)
2314 IOPMRequest
* request
;
2315 bool noPowerChange
= true;
2317 if ( initialized
&& stateNumber
&& (type
== kIOPMSuperclassPolicy1
) )
2319 IOLockLock(fActivityLock
);
2321 // Record device activity for the idle timer handler.
2323 fDeviceActive
= true;
2324 clock_get_uptime(&fDeviceActiveTimestamp
);
2326 // Record the last tickle power state.
2327 // This helps to filter out redundant tickles as
2328 // this function may be called from the data path.
2330 if (fActivityTicklePowerState
< (long)stateNumber
)
2332 fActivityTicklePowerState
= stateNumber
;
2333 noPowerChange
= false;
2335 request
= acquirePMRequest( this, kIOPMRequestTypeActivityTickle
);
2338 request
->fArg0
= (void *) stateNumber
; // power state
2339 request
->fArg1
= (void *) true; // power rise
2340 submitPMRequest(request
);
2344 IOLockUnlock(fActivityLock
);
2347 // Returns false if the activityTickle might cause a transition to a
2348 // higher powered state, true otherwise.
2350 return noPowerChange
;
2353 //*********************************************************************************
2354 // [public virtual] setIdleTimerPeriod
2356 // A subclass policy-maker is going to use our standard idleness
2357 // detection service. Make a command queue and an idle timer and
2358 // connect them to the power management workloop. Finally,
2360 //*********************************************************************************
2362 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
2364 IOWorkLoop
* wl
= getPMworkloop();
2366 if (!initialized
|| !wl
)
2367 return IOPMNotYetInitialized
;
2369 OUR_PMLog(PMsetIdleTimerPeriod
, period
, 0);
2371 fIdleTimerPeriod
= period
;
2375 // make the timer event
2376 if ( fIdleTimerEventSource
== NULL
)
2378 IOTimerEventSource
* timerSrc
;
2380 timerSrc
= IOTimerEventSource::timerEventSource(
2381 this, PM_idle_timer_expired
);
2383 if (timerSrc
&& (wl
->addEventSource(timerSrc
) != kIOReturnSuccess
))
2385 timerSrc
->release();
2389 fIdleTimerEventSource
= timerSrc
;
2392 start_PM_idle_timer();
2397 //******************************************************************************
2398 // [public virtual] nextIdleTimeout
2400 // Returns how many "seconds from now" the device should idle into its
2401 // next lowest power state.
2402 //******************************************************************************
2404 SInt32
IOService::nextIdleTimeout(
2405 AbsoluteTime currentTime
,
2406 AbsoluteTime lastActivity
,
2407 unsigned int powerState
)
2414 // Calculate time difference using funky macro from clock.h.
2415 delta
= currentTime
;
2416 SUB_ABSOLUTETIME(&delta
, &lastActivity
);
2418 // Figure it in seconds.
2419 absolutetime_to_nanoseconds(delta
, &delta_ns
);
2420 delta_secs
= (SInt32
)(delta_ns
/ NSEC_PER_SEC
);
2422 // Be paranoid about delta somehow exceeding timer period.
2423 if (delta_secs
< (int) fIdleTimerPeriod
)
2424 delay_secs
= (int) fIdleTimerPeriod
- delta_secs
;
2426 delay_secs
= (int) fIdleTimerPeriod
;
2428 return (SInt32
)delay_secs
;
2431 //******************************************************************************
2432 // [public virtual] start_PM_idle_timer
2434 // The parameter is a pointer to us. Use it to call our timeout method.
2435 //******************************************************************************
2437 void IOService::start_PM_idle_timer ( void )
2439 static const int maxTimeout
= 100000;
2440 static const int minTimeout
= 1;
2441 AbsoluteTime uptime
;
2444 if (!initialized
|| !fIdleTimerEventSource
)
2447 IOLockLock(fActivityLock
);
2449 clock_get_uptime(&uptime
);
2451 // Subclasses may modify idle sleep algorithm
2452 idle_in
= nextIdleTimeout(uptime
, fDeviceActiveTimestamp
, fCurrentPowerState
);
2454 // Check for out-of range responses
2455 if (idle_in
> maxTimeout
)
2457 // use standard implementation
2458 idle_in
= IOService::nextIdleTimeout(uptime
,
2459 fDeviceActiveTimestamp
,
2460 fCurrentPowerState
);
2461 } else if (idle_in
< minTimeout
) {
2462 idle_in
= fIdleTimerPeriod
;
2465 IOLockUnlock(fActivityLock
);
2467 fIdleTimerEventSource
->setTimeout(idle_in
, NSEC_PER_SEC
);
2470 //*********************************************************************************
2471 // [private] PM_idle_timer_expired
2473 // The parameter is a pointer to us. Use it to call our timeout method.
2474 //*********************************************************************************
2476 void PM_idle_timer_expired ( OSObject
* ourSelves
, IOTimerEventSource
* )
2478 ((IOService
*)ourSelves
)->PM_idle_timer_expiration();
2481 //*********************************************************************************
2482 // [public virtual] PM_idle_timer_expiration
2484 // The idle timer has expired. If there has been activity since the last
2485 // expiration, just restart the timer and return. If there has not been
2486 // activity, switch to the next lower power state and restart the timer.
2487 //*********************************************************************************
2489 void IOService::PM_idle_timer_expiration ( void )
2491 IOPMRequest
* request
;
2492 bool restartTimer
= true;
2494 if ( !initialized
|| !fIdleTimerPeriod
)
2497 IOLockLock(fActivityLock
);
2499 // Check for device activity (tickles) over last timer period.
2503 // Device was active - do not drop power, restart timer.
2504 fDeviceActive
= false;
2508 // No device activity - drop power state by one level.
2509 // Decrement the cached tickle power state when possible.
2510 // This value may be (-1) before activityTickle() is called,
2511 // but the power drop request must be issued regardless.
2513 if (fActivityTicklePowerState
> 0)
2515 fActivityTicklePowerState
--;
2518 request
= acquirePMRequest( this, kIOPMRequestTypeActivityTickle
);
2521 request
->fArg0
= (void *) 0; // power state (irrelevant)
2522 request
->fArg1
= (void *) false; // power drop
2523 submitPMRequest( request
);
2525 // Do not restart timer until after the tickle request has been
2528 restartTimer
= false;
2532 IOLockUnlock(fActivityLock
);
2535 start_PM_idle_timer();
2538 //*********************************************************************************
2539 // [public virtual] command_received
2541 //*********************************************************************************
2543 void IOService::command_received ( void *statePtr
, void *, void * , void * )
2547 //*********************************************************************************
2548 // [public virtual] setAggressiveness
2550 // Pass on the input parameters to all power domain children. All those which are
2551 // power domains will pass it on to their children, etc.
2552 //*********************************************************************************
2554 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
2558 IOPowerConnection
* connection
;
2562 return IOPMNotYetInitialized
;
2564 if (getPMRootDomain() == this)
2565 OUR_PMLog(kPMLogSetAggressiveness
, type
, newLevel
);
2567 if ( type
<= kMaxType
)
2569 fAggressivenessValue
[type
] = newLevel
;
2570 fAggressivenessValid
[type
] = true;
2573 iter
= getChildIterator(gIOPowerPlane
);
2576 while ( (next
= iter
->getNextObject()) )
2578 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
2580 if (connection
->getReadyFlag() == false)
2582 PM_CONNECT("[%s] %s: connection not ready\n",
2583 getName(), __FUNCTION__
);
2587 child
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
2590 child
->setAggressiveness(type
, newLevel
);
2601 //*********************************************************************************
2602 // [public virtual] getAggressiveness
2604 // Called by the user client.
2605 //*********************************************************************************
2607 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
2609 if ( !initialized
|| (type
> kMaxType
) )
2610 return kIOReturnBadArgument
;
2612 if ( !fAggressivenessValid
[type
] )
2613 return kIOReturnInvalid
;
2615 *currentLevel
= fAggressivenessValue
[type
];
2617 return kIOReturnSuccess
;
2620 //*********************************************************************************
2621 // [public] getPowerState
2623 //*********************************************************************************
2625 UInt32
IOService::getPowerState ( void )
2630 return fCurrentPowerState
;
2633 //*********************************************************************************
2634 // [public virtual] systemWake
2636 // Pass this to all power domain children. All those which are
2637 // power domains will pass it on to their children, etc.
2638 //*********************************************************************************
2640 IOReturn
IOService::systemWake ( void )
2644 IOPowerConnection
* connection
;
2645 IOService
* theChild
;
2647 OUR_PMLog(kPMLogSystemWake
, 0, 0);
2649 iter
= getChildIterator(gIOPowerPlane
);
2652 while ( (next
= iter
->getNextObject()) )
2654 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
2656 if (connection
->getReadyFlag() == false)
2658 PM_CONNECT("[%s] %s: connection not ready\n",
2659 getName(), __FUNCTION__
);
2663 theChild
= (IOService
*)connection
->copyChildEntry(gIOPowerPlane
);
2666 theChild
->systemWake();
2667 theChild
->release();
2674 if ( fControllingDriver
!= NULL
)
2676 if ( fControllingDriver
->didYouWakeSystem() )
2685 //*********************************************************************************
2686 // [public virtual] temperatureCriticalForZone
2687 //*********************************************************************************
2689 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
2691 IOService
* theParent
;
2694 OUR_PMLog(kPMLogCriticalTemp
, 0, 0);
2696 if ( inPlane(gIOPowerPlane
) && !fWeAreRoot
)
2698 theNub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
2701 theParent
= (IOService
*)theNub
->copyParentEntry(gIOPowerPlane
);
2705 theParent
->temperatureCriticalForZone(whichZone
);
2706 theParent
->release();
2713 //*********************************************************************************
2714 // [public] powerOverrideOnPriv
2715 //*********************************************************************************
2717 IOReturn
IOService::powerOverrideOnPriv ( void )
2719 IOPMRequest
* request
;
2722 return IOPMNotYetInitialized
;
2724 if (gIOPMWorkLoop
->inGate())
2726 fDeviceOverrides
= true;
2730 request
= acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv
);
2732 return kIOReturnNoMemory
;
2734 submitPMRequest( request
);
2738 //*********************************************************************************
2739 // [public] powerOverrideOffPriv
2740 //*********************************************************************************
2742 IOReturn
IOService::powerOverrideOffPriv ( void )
2744 IOPMRequest
* request
;
2747 return IOPMNotYetInitialized
;
2749 if (gIOPMWorkLoop
->inGate())
2751 fDeviceOverrides
= false;
2755 request
= acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv
);
2757 return kIOReturnNoMemory
;
2759 submitPMRequest( request
);
2763 //*********************************************************************************
2764 // [private] handlePowerOverrideChanged
2765 //*********************************************************************************
2767 void IOService::handlePowerOverrideChanged ( IOPMRequest
* request
)
2769 PM_ASSERT_IN_GATE();
2770 if (request
->getType() == kIOPMRequestTypePowerOverrideOnPriv
)
2772 OUR_PMLog(kPMLogOverrideOn
, 0, 0);
2773 fDeviceOverrides
= true;
2777 OUR_PMLog(kPMLogOverrideOff
, 0, 0);
2778 fDeviceOverrides
= false;
2781 if (fControllingDriver
&& inPlane(gIOPowerPlane
) && fParentsKnowState
)
2783 computeDesiredState();
2788 //*********************************************************************************
2789 // [private] enqueuePowerChange
2790 //*********************************************************************************
2792 IOReturn
IOService::enqueuePowerChange (
2793 unsigned long flags
,
2794 unsigned long whatStateOrdinal
,
2795 unsigned long domainState
,
2796 IOPowerConnection
* whichParent
,
2797 unsigned long singleParentState
)
2799 changeNoteItem changeNote
;
2800 IOPMPowerState
* powerStatePtr
;
2802 PM_ASSERT_IN_GATE();
2803 assert( fMachineState
== kIOPM_Finished
);
2804 assert( whatStateOrdinal
< fNumberOfPowerStates
);
2806 if (whatStateOrdinal
>= fNumberOfPowerStates
)
2807 return IOPMAckImplied
;
2809 powerStatePtr
= &fPowerStates
[whatStateOrdinal
];
2811 // Initialize the change note
2812 changeNote
.flags
= flags
;
2813 changeNote
.newStateNumber
= whatStateOrdinal
;
2814 changeNote
.outputPowerCharacter
= powerStatePtr
->outputPowerCharacter
;
2815 changeNote
.inputPowerRequirement
= powerStatePtr
->inputPowerRequirement
;
2816 changeNote
.capabilityFlags
= powerStatePtr
->capabilityFlags
;
2817 changeNote
.parent
= NULL
;
2819 if (flags
& IOPMParentInitiated
)
2821 changeNote
.domainState
= domainState
;
2822 changeNote
.parent
= whichParent
;
2823 changeNote
.singleParentState
= singleParentState
;
2826 if (flags
& IOPMWeInitiated
)
2828 start_our_change(&changeNote
);
2833 return start_parent_change(&changeNote
);
2837 //*********************************************************************************
2838 // [private] notifyInterestedDrivers
2839 //*********************************************************************************
2841 bool IOService::notifyInterestedDrivers ( void )
2843 IOPMinformee
* informee
;
2844 IOPMinformeeList
* list
= fInterestedDrivers
;
2845 DriverCallParam
* param
;
2848 PM_ASSERT_IN_GATE();
2849 assert( fDriverCallBusy
== false );
2850 assert( fDriverCallParamCount
== 0 );
2851 assert( fHeadNotePendingAcks
== 0 );
2853 count
= list
->numberOfItems();
2855 goto done
; // no interested drivers
2857 // Allocate an array of interested drivers and their return values
2858 // for the callout thread. Everything else is still "owned" by the
2859 // PM work loop, which can run to process acknowledgePowerChange()
2862 param
= (DriverCallParam
*) fDriverCallParamPtr
;
2863 if (count
> fDriverCallParamSlots
)
2865 if (fDriverCallParamSlots
)
2867 assert(fDriverCallParamPtr
);
2868 IODelete(fDriverCallParamPtr
, DriverCallParam
, fDriverCallParamSlots
);
2869 fDriverCallParamPtr
= 0;
2870 fDriverCallParamSlots
= 0;
2873 param
= IONew(DriverCallParam
, count
);
2875 goto done
; // no memory
2877 fDriverCallParamPtr
= (void *) param
;
2878 fDriverCallParamSlots
= count
;
2881 informee
= list
->firstInList();
2883 for (IOItemCount i
= 0; i
< count
; i
++)
2885 informee
->timer
= -1;
2886 param
[i
].Target
= informee
;
2888 informee
= list
->nextInList( informee
);
2891 fDriverCallParamCount
= count
;
2892 fHeadNotePendingAcks
= count
;
2894 // Machine state will be blocked pending callout thread completion.
2897 fDriverCallBusy
= true;
2899 thread_call_enter( fDriverCallEntry
);
2903 // no interested drivers or did not schedule callout thread due to error.
2907 //*********************************************************************************
2908 // [private] notifyInterestedDriversDone
2909 //*********************************************************************************
2911 void IOService::notifyInterestedDriversDone ( void )
2913 IOPMinformee
* informee
;
2915 DriverCallParam
* param
;
2918 PM_ASSERT_IN_GATE();
2919 param
= (DriverCallParam
*) fDriverCallParamPtr
;
2920 count
= fDriverCallParamCount
;
2922 assert( fDriverCallBusy
== false );
2923 assert( fMachineState
== kIOPM_DriverThreadCallDone
);
2927 for (IOItemCount i
= 0; i
< count
; i
++, param
++)
2929 informee
= (IOPMinformee
*) param
->Target
;
2930 result
= param
->Result
;
2932 if ((result
== IOPMAckImplied
) || (result
< 0))
2934 // child return IOPMAckImplied
2935 informee
->timer
= 0;
2936 fHeadNotePendingAcks
--;
2938 else if (informee
->timer
)
2940 assert(informee
->timer
== -1);
2942 // Driver has not acked, and has returned a positive result.
2943 // Enforce a minimum permissible timeout value.
2944 // Make the min value large enough so timeout is less likely
2945 // to occur if a driver misinterpreted that the return value
2946 // should be in microsecond units. And make it large enough
2947 // to be noticeable if a driver neglects to ack.
2949 if (result
< kMinAckTimeoutTicks
)
2950 result
= kMinAckTimeoutTicks
;
2952 informee
->timer
= (result
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
2954 // else, child has already acked or driver has removed interest,
2955 // and head_note_pendingAcks decremented.
2956 // informee may have been removed from the interested drivers list,
2957 // thus the informee must be retained across the callout.
2959 informee
->release();
2962 fDriverCallParamCount
= 0;
2964 if ( fHeadNotePendingAcks
)
2966 OUR_PMLog(kPMLogStartAckTimer
, 0, 0);
2971 // Hop back to original machine state path (from notifyAll)
2972 fMachineState
= fNextMachineState
;
2977 //*********************************************************************************
2978 // [private] notifyChildren
2979 //*********************************************************************************
2981 void IOService::notifyChildren ( void )
2985 IOPowerConnection
* connection
;
2986 OSArray
* children
= 0;
2988 if (fStrictTreeOrder
)
2989 children
= OSArray::withCapacity(8);
2991 // Sum child power consumption in notifyChild()
2992 fPowerStates
[fHeadNoteState
].staticPower
= 0;
2994 iter
= getChildIterator(gIOPowerPlane
);
2997 while ((next
= iter
->getNextObject()))
2999 if ((connection
= OSDynamicCast(IOPowerConnection
, next
)))
3001 if (connection
->getReadyFlag() == false)
3003 PM_CONNECT("[%s] %s: connection not ready\n",
3004 getName(), __FUNCTION__
);
3009 children
->setObject( connection
);
3011 notifyChild( connection
,
3012 fDriverCallReason
== kDriverCallInformPreChange
);
3020 if (children
->getCount() == 0)
3022 children
->release();
3027 assert(fNotifyChildArray
== 0);
3028 fNotifyChildArray
= children
;
3029 fNextMachineState
= fMachineState
;
3030 fMachineState
= kIOPM_NotifyChildrenDone
;
3035 //*********************************************************************************
3036 // [private] notifyChildrenDone
3037 //*********************************************************************************
3039 void IOService::notifyChildrenDone ( void )
3041 PM_ASSERT_IN_GATE();
3042 assert(fNotifyChildArray
);
3043 assert(fMachineState
== kIOPM_NotifyChildrenDone
);
3045 // Interested drivers have all acked (if any), ack timer stopped.
3046 // Notify one child, wait for it's ack, then repeat for next child.
3047 // This is a workaround for some drivers with multiple instances at
3048 // the same branch in the power tree, but the driver is slow to power
3049 // up unless the tree ordering is observed. Problem observed only on
3050 // system wake, not on system sleep.
3052 // We have the ability to power off in reverse child index order.
3053 // That works nicely on some machines, but not on all HW configs.
3055 if (fNotifyChildArray
->getCount())
3057 IOPowerConnection
* connection
;
3058 connection
= (IOPowerConnection
*) fNotifyChildArray
->getObject(0);
3059 fNotifyChildArray
->removeObject(0);
3060 notifyChild( connection
, fDriverCallReason
== kDriverCallInformPreChange
);
3064 fNotifyChildArray
->release();
3065 fNotifyChildArray
= 0;
3066 fMachineState
= fNextMachineState
;
3070 //*********************************************************************************
3071 // [private] notifyAll
3072 //*********************************************************************************
3074 IOReturn
IOService::notifyAll ( bool is_prechange
)
3076 // Save the next machine_state to be restored by notifyInterestedDriversDone()
3078 PM_ASSERT_IN_GATE();
3079 fNextMachineState
= fMachineState
;
3080 fMachineState
= kIOPM_DriverThreadCallDone
;
3081 fDriverCallReason
= is_prechange
?
3082 kDriverCallInformPreChange
: kDriverCallInformPostChange
;
3084 if (!notifyInterestedDrivers())
3085 notifyInterestedDriversDone();
3087 return IOPMWillAckLater
;
3090 //*********************************************************************************
3091 // [private, static] pmDriverCallout
3093 // Thread call context
3094 //*********************************************************************************
3096 IOReturn
IOService::actionDriverCalloutDone (
3098 void * arg0
, void * arg1
,
3099 void * arg2
, void * arg3
)
3101 IOServicePM
* pwrMgt
= (IOServicePM
*) arg0
;
3104 fDriverCallBusy
= false;
3107 if (gIOPMReplyQueue
)
3108 gIOPMReplyQueue
->signalWorkAvailable();
3110 return kIOReturnSuccess
;
3113 void IOService::pmDriverCallout ( IOService
* from
)
3116 switch (from
->fDriverCallReason
)
3118 case kDriverCallSetPowerState
:
3119 from
->driverSetPowerState();
3122 case kDriverCallInformPreChange
:
3123 case kDriverCallInformPostChange
:
3124 from
->driverInformPowerChange();
3128 IOPanic("IOService::pmDriverCallout bad machine state");
3131 gIOPMWorkLoop
->runAction(actionDriverCalloutDone
,
3133 /* arg0 */ (void *) from
->pwrMgt
);
3136 //*********************************************************************************
3137 // [private] driverSetPowerState
3139 // Thread call context
3140 //*********************************************************************************
3142 void IOService::driverSetPowerState ( void )
3145 unsigned long powerState
;
3146 DriverCallParam
* param
;
3150 assert( fDriverCallBusy
);
3151 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3153 assert( fDriverCallParamCount
== 1 );
3155 driver
= fControllingDriver
;
3156 powerState
= fHeadNoteState
;
3160 OUR_PMLog( kPMLogProgramHardware
, (UInt32
) this, powerState
);
3161 clock_get_uptime(&fDriverCallStartTime
);
3162 result
= driver
->setPowerState( powerState
, this );
3163 clock_get_uptime(&end
);
3164 OUR_PMLog((UInt32
) -kPMLogProgramHardware
, (UInt32
) this, (UInt32
) result
);
3166 #if LOG_SETPOWER_TIMES
3167 if ((result
== IOPMAckImplied
) || (result
< 0))
3171 SUB_ABSOLUTETIME(&end
, &fDriverCallStartTime
);
3172 absolutetime_to_nanoseconds(end
, &nsec
);
3173 if (nsec
> LOG_SETPOWER_TIMES
)
3174 PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
3175 fName
, this, fCurrentPowerState
, powerState
, NS_TO_MS(nsec
));
3180 result
= kIOPMAckImplied
;
3182 param
->Result
= result
;
3185 //*********************************************************************************
3186 // [private] driverInformPowerChange
3188 // Thread call context
3189 //*********************************************************************************
3191 void IOService::driverInformPowerChange ( void )
3194 IOPMinformee
* informee
;
3197 IOPMPowerFlags powerFlags
;
3198 unsigned long powerState
;
3199 DriverCallParam
* param
;
3202 assert( fDriverCallBusy
);
3203 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3204 count
= fDriverCallParamCount
;
3205 assert( count
&& param
);
3207 powerFlags
= fHeadNoteCapabilityFlags
;
3208 powerState
= fHeadNoteState
;
3210 for (IOItemCount i
= 0; i
< count
; i
++)
3212 informee
= (IOPMinformee
*) param
->Target
;
3213 driver
= informee
->whatObject
;
3215 if (!fWillPMStop
&& informee
->active
)
3217 if (fDriverCallReason
== kDriverCallInformPreChange
)
3219 OUR_PMLog(kPMLogInformDriverPreChange
, (UInt32
) this, powerState
);
3220 clock_get_uptime(&informee
->startTime
);
3221 result
= driver
->powerStateWillChangeTo(powerFlags
, powerState
, this);
3222 clock_get_uptime(&end
);
3223 OUR_PMLog((UInt32
)-kPMLogInformDriverPreChange
, (UInt32
) this, result
);
3227 OUR_PMLog(kPMLogInformDriverPostChange
, (UInt32
) this, powerState
);
3228 clock_get_uptime(&informee
->startTime
);
3229 result
= driver
->powerStateDidChangeTo(powerFlags
, powerState
, this);
3230 clock_get_uptime(&end
);
3231 OUR_PMLog((UInt32
)-kPMLogInformDriverPostChange
, (UInt32
) this, result
);
3234 #if LOG_SETPOWER_TIMES
3235 if ((result
== IOPMAckImplied
) || (result
< 0))
3239 SUB_ABSOLUTETIME(&end
, &informee
->startTime
);
3240 absolutetime_to_nanoseconds(end
, &nsec
);
3241 if (nsec
> LOG_SETPOWER_TIMES
)
3242 PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
3244 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
3245 driver
, fName
, fCurrentPowerState
, powerState
, NS_TO_MS(nsec
));
3250 result
= kIOPMAckImplied
;
3252 param
->Result
= result
;
3257 //*********************************************************************************
3258 // [private] notifyChild
3260 // Notify a power domain child of an upcoming power change.
3261 // If the object acknowledges the current change, we return TRUE.
3262 //*********************************************************************************
3264 bool IOService::notifyChild ( IOPowerConnection
* theNub
, bool is_prechange
)
3266 IOReturn k
= IOPMAckImplied
;
3267 unsigned long childPower
;
3268 IOService
* theChild
;
3269 IOPMRequest
* childRequest
;
3272 PM_ASSERT_IN_GATE();
3273 theChild
= (IOService
*)(theNub
->copyChildEntry(gIOPowerPlane
));
3280 // Unless the child handles the notification immediately and returns
3281 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
3282 fHeadNotePendingAcks
++;
3283 theNub
->setAwaitingAck(true);
3285 requestType
= is_prechange
?
3286 kIOPMRequestTypePowerDomainWillChange
:
3287 kIOPMRequestTypePowerDomainDidChange
;
3289 childRequest
= acquirePMRequest( theChild
, requestType
);
3293 childRequest
->fArg0
= (void *) fHeadNoteOutputFlags
;
3294 childRequest
->fArg1
= (void *) theNub
;
3295 childRequest
->fArg2
= (void *) (fHeadNoteState
< fCurrentPowerState
);
3296 theChild
->submitPMRequest( childRequest
);
3297 k
= IOPMWillAckLater
;
3302 fHeadNotePendingAcks
--;
3303 theNub
->setAwaitingAck(false);
3304 childPower
= theChild
->currentPowerConsumption();
3305 if ( childPower
== kIOPMUnknown
)
3307 fPowerStates
[fHeadNoteState
].staticPower
= kIOPMUnknown
;
3309 if ( fPowerStates
[fHeadNoteState
].staticPower
!= kIOPMUnknown
)
3311 fPowerStates
[fHeadNoteState
].staticPower
+= childPower
;
3316 theChild
->release();
3317 return (k
== IOPMAckImplied
);
3320 //*********************************************************************************
3321 // [private] OurChangeTellClientsPowerDown
3323 // All registered applications and kernel clients have positively acknowledged our
3324 // intention of lowering power. Here we notify them all that we will definitely
3325 // lower the power. If we don't have to wait for any of them to acknowledge, we
3326 // carry on by notifying interested drivers. Otherwise, we do wait.
3327 //*********************************************************************************
3329 void IOService::OurChangeTellClientsPowerDown ( void )
3331 fMachineState
= kIOPM_OurChangeTellPriorityClientsPowerDown
;
3332 tellChangeDown1(fHeadNoteState
);
3335 //*********************************************************************************
3336 // [private] OurChangeTellPriorityClientsPowerDown
3338 // All registered applications and kernel clients have positively acknowledged our
3339 // intention of lowering power. Here we notify "priority" clients that we are
3340 // lowering power. If we don't have to wait for any of them to acknowledge, we
3341 // carry on by notifying interested drivers. Otherwise, we do wait.
3342 //*********************************************************************************
3344 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
3346 fMachineState
= kIOPM_OurChangeNotifyInterestedDriversWillChange
;
3347 tellChangeDown2(fHeadNoteState
);
3350 //*********************************************************************************
3351 // [private] OurChangeNotifyInterestedDriversWillChange
3353 // All registered applications and kernel clients have acknowledged our notification
3354 // that we are lowering power. Here we notify interested drivers. If we don't have
3355 // to wait for any of them to acknowledge, we instruct our power driver to make the
3356 // change. Otherwise, we do wait.
3357 //*********************************************************************************
3359 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
3361 fMachineState
= kIOPM_OurChangeSetPowerState
;
3365 //*********************************************************************************
3366 // [private] OurChangeSetPowerState
3368 // All interested drivers have acknowledged our pre-change notification of a power
3369 // change we initiated. Here we instruct our controlling driver to make
3370 // the change to the hardware. If it does so, we continue processing
3371 // (waiting for settle and notifying interested parties post-change.)
3372 // If it doesn't, we have to wait for it to acknowledge and then continue.
3373 //*********************************************************************************
3375 void IOService::OurChangeSetPowerState ( void )
3377 fNextMachineState
= kIOPM_OurChangeWaitForPowerSettle
;
3378 fMachineState
= kIOPM_DriverThreadCallDone
;
3379 fDriverCallReason
= kDriverCallSetPowerState
;
3381 if (notifyControllingDriver() == false)
3382 notifyControllingDriverDone();
3385 //*********************************************************************************
3386 // [private] OurChangeWaitForPowerSettle
3388 // Our controlling driver has changed power state on the hardware
3389 // during a power change we initiated. Here we see if we need to wait
3390 // for power to settle before continuing. If not, we continue processing
3391 // (notifying interested parties post-change). If so, we wait and
3393 //*********************************************************************************
3395 void IOService::OurChangeWaitForPowerSettle ( void )
3397 fMachineState
= kIOPM_OurChangeNotifyInterestedDriversDidChange
;
3398 fSettleTimeUS
= compute_settle_time();
3399 if ( fSettleTimeUS
)
3401 startSettleTimer(fSettleTimeUS
);
3405 //*********************************************************************************
3406 // [private] OurChangeNotifyInterestedDriversDidChange
3408 // Power has settled on a power change we initiated. Here we notify
3409 // all our interested parties post-change. If they all acknowledge, we're
3410 // done with this change note, and we can start on the next one.
3411 // Otherwise we have to wait for acknowledgements and finish up later.
3412 //*********************************************************************************
3414 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
3416 fMachineState
= kIOPM_OurChangeFinish
;
3420 //*********************************************************************************
3421 // [private] OurChangeFinish
3423 // Power has settled on a power change we initiated, and
3424 // all our interested parties have acknowledged. We're
3425 // done with this change note, and we can start on the next one.
3426 //*********************************************************************************
3428 void IOService::OurChangeFinish ( void )
3433 //*********************************************************************************
3434 // [private] ParentDownTellPriorityClientsPowerDown
3436 // All applications and kernel clients have been notified of a power lowering
3437 // initiated by the parent and we had to wait for responses. Here
3438 // we notify any priority clients. If they all ack, we continue with the power change.
3439 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
3440 //*********************************************************************************
3442 void IOService::ParentDownTellPriorityClientsPowerDown ( void )
3444 fMachineState
= kIOPM_ParentDownNotifyInterestedDriversWillChange
;
3445 tellChangeDown2(fHeadNoteState
);
3448 //*********************************************************************************
3449 // [private] ParentDownNotifyInterestedDriversWillChange
3451 // All applications and kernel clients have been notified of a power lowering
3452 // initiated by the parent and we had to wait for their responses. Here we notify
3453 // any interested drivers and power domain children. If they all ack, we continue
3454 // with the power change.
3455 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
3456 //*********************************************************************************
3458 void IOService::ParentDownNotifyInterestedDriversWillChange ( void )
3460 fMachineState
= kIOPM_ParentDownSetPowerState
;
3464 //*********************************************************************************
3465 // [private] ParentDownSetPowerState
3467 // We had to wait for it, but all parties have acknowledged our pre-change
3468 // notification of a power lowering initiated by the parent.
3469 // Here we instruct our controlling driver
3470 // to put the hardware in the state it needs to be in when the domain is
3471 // lowered. If it does so, we continue processing
3472 // (waiting for settle and acknowledging the parent.)
3473 // If it doesn't, we have to wait for it to acknowledge and then continue.
3474 //*********************************************************************************
3476 void IOService::ParentDownSetPowerState ( void )
3478 fNextMachineState
= kIOPM_ParentDownWaitForPowerSettle
;
3479 fMachineState
= kIOPM_DriverThreadCallDone
;
3480 fDriverCallReason
= kDriverCallSetPowerState
;
3482 if (notifyControllingDriver() == false)
3483 notifyControllingDriverDone();
3486 //*********************************************************************************
3487 // [private] ParentDownWaitForPowerSettle
3489 // Our controlling driver has changed power state on the hardware
3490 // during a power change initiated by our parent. We have had to wait
3491 // for acknowledgement from interested parties, or we have had to wait
3492 // for the controlling driver to change the state. Here we see if we need
3493 // to wait for power to settle before continuing. If not, we continue
3494 // processing (acknowledging our preparedness to the parent).
3495 // If so, we wait and continue later.
3496 //*********************************************************************************
3498 void IOService::ParentDownWaitForPowerSettle ( void )
3500 fMachineState
= kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange
;
3501 fSettleTimeUS
= compute_settle_time();
3502 if ( fSettleTimeUS
)
3504 startSettleTimer(fSettleTimeUS
);
3508 //*********************************************************************************
3509 // [private] ParentDownNotifyDidChangeAndAcknowledgeChange
3511 // Power has settled on a power change initiated by our parent. Here we
3512 // notify interested parties.
3513 //*********************************************************************************
3515 void IOService::ParentDownNotifyDidChangeAndAcknowledgeChange ( void )
3517 fMachineState
= kIOPM_ParentDownAcknowledgeChange
;
3521 //*********************************************************************************
3522 // [private] ParentDownAcknowledgeChange
3524 // We had to wait for it, but all parties have acknowledged our post-change
3525 // notification of a power lowering initiated by the parent.
3526 // Here we acknowledge the parent.
3527 // We are done with this change note, and we can start on the next one.
3528 //*********************************************************************************
3530 void IOService::ParentDownAcknowledgeChange ( void )
3532 IORegistryEntry
* nub
;
3535 nub
= fHeadNoteParent
;
3538 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
3541 parent
->acknowledgePowerChange((IOService
*)nub
);
3547 //*********************************************************************************
3548 // [private] ParentUpSetPowerState
3550 // Our parent has informed us via powerStateDidChange that it has
3551 // raised the power in our power domain, and we have had to wait
3552 // for some interested party to acknowledge our notification.
3553 // Here we instruct our controlling
3554 // driver to program the hardware to take advantage of the higher domain
3555 // power. If it does so, we continue processing
3556 // (waiting for settle and notifying interested parties post-change.)
3557 // If it doesn't, we have to wait for it to acknowledge and then continue.
3558 //*********************************************************************************
3560 void IOService::ParentUpSetPowerState ( void )
3562 fNextMachineState
= kIOPM_ParentUpWaitForSettleTime
;
3563 fMachineState
= kIOPM_DriverThreadCallDone
;
3564 fDriverCallReason
= kDriverCallSetPowerState
;
3566 if (notifyControllingDriver() == false)
3567 notifyControllingDriverDone();
3570 //*********************************************************************************
3571 // [private] ParentUpWaitForSettleTime
3573 // Our controlling driver has changed power state on the hardware
3574 // during a power raise initiated by the parent, but we had to wait for it.
3575 // Here we see if we need to wait for power to settle before continuing.
3576 // If not, we continue processing (notifying interested parties post-change).
3577 // If so, we wait and continue later.
3578 //*********************************************************************************
3580 void IOService::ParentUpWaitForSettleTime ( void )
3582 fMachineState
= kIOPM_ParentUpNotifyInterestedDriversDidChange
;
3583 fSettleTimeUS
= compute_settle_time();
3584 if ( fSettleTimeUS
)
3586 startSettleTimer(fSettleTimeUS
);
3590 //*********************************************************************************
3591 // [private] ParentUpNotifyInterestedDriversDidChange
3593 // Power has settled on a power raise initiated by the parent.
3594 // Here we notify all our interested parties post-change. If they all acknowledge,
3595 // we're done with this change note, and we can start on the next one.
3596 // Otherwise we have to wait for acknowledgements and finish up later.
3597 //*********************************************************************************
3599 void IOService::ParentUpNotifyInterestedDriversDidChange ( void )
3601 fMachineState
= kIOPM_ParentUpAcknowledgePowerChange
;
3605 //*********************************************************************************
3606 // [private] ParentUpAcknowledgePowerChange
3608 // All parties have acknowledged our post-change notification of a power
3609 // raising initiated by the parent. Here we acknowledge the parent.
3610 // We are done with this change note, and we can start on the next one.
3611 //*********************************************************************************
3613 void IOService::ParentUpAcknowledgePowerChange ( void )
3615 IORegistryEntry
* nub
;
3618 nub
= fHeadNoteParent
;
3621 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
3624 parent
->acknowledgePowerChange((IOService
*)nub
);
3630 //*********************************************************************************
3631 // [private] all_done
3633 // A power change is complete, and the used post-change note is at
3634 // the head of the queue. Remove it and set myCurrentState to the result
3635 // of the change. Start up the next change in queue.
3636 //*********************************************************************************
3638 void IOService::all_done ( void )
3640 unsigned long previous_state
;
3642 fMachineState
= kIOPM_Finished
;
3645 if ( fHeadNoteFlags
& IOPMWeInitiated
)
3647 // could our driver switch to the new state?
3648 if ( !( fHeadNoteFlags
& IOPMNotDone
) )
3650 // we changed, tell our parent
3653 ask_parent(fHeadNoteState
);
3656 // yes, did power raise?
3657 if ( fCurrentPowerState
< fHeadNoteState
)
3659 // yes, inform clients and apps
3660 tellChangeUp (fHeadNoteState
);
3662 previous_state
= fCurrentPowerState
;
3664 fCurrentPowerState
= fHeadNoteState
;
3666 fPMVars
->myCurrentState
= fCurrentPowerState
;
3668 OUR_PMLog(kPMLogChangeDone
, fCurrentPowerState
, 0);
3670 // inform subclass policy-maker
3671 if (!fWillPMStop
&& fParentsKnowState
)
3672 powerChangeDone(previous_state
);
3674 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
3678 // parent's power change
3679 if ( fHeadNoteFlags
& IOPMParentInitiated
)
3681 if (((fHeadNoteFlags
& IOPMDomainWillChange
) && (fCurrentPowerState
>= fHeadNoteState
)) ||
3682 ((fHeadNoteFlags
& IOPMDomainDidChange
) && (fCurrentPowerState
< fHeadNoteState
)))
3685 if ( fCurrentPowerState
< fHeadNoteState
)
3687 // yes, inform clients and apps
3688 tellChangeUp (fHeadNoteState
);
3691 previous_state
= fCurrentPowerState
;
3692 fCurrentPowerState
= fHeadNoteState
;
3694 fPMVars
->myCurrentState
= fCurrentPowerState
;
3696 fMaxCapability
= fControllingDriver
->maxCapabilityForDomainState(fHeadNoteDomainState
);
3698 OUR_PMLog(kPMLogChangeDone
, fCurrentPowerState
, 0);
3700 // inform subclass policy-maker
3701 if (!fWillPMStop
&& fParentsKnowState
)
3702 powerChangeDone(previous_state
);
3704 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
3708 if (fCurrentPowerState
< fNumberOfPowerStates
)
3710 const IOPMPowerState
* powerStatePtr
= &fPowerStates
[fCurrentPowerState
];
3712 fCurrentCapabilityFlags
= powerStatePtr
->capabilityFlags
;
3713 if (fCurrentCapabilityFlags
& kIOPMStaticPowerValid
)
3714 fCurrentPowerConsumption
= powerStatePtr
->staticPower
;
3717 // When power rises enough to satisfy the tickle's desire for more power,
3718 // the condition preventing idle-timer from dropping power is removed.
3720 if (fCurrentPowerState
>= fIdleTimerMinPowerState
)
3722 fIdleTimerMinPowerState
= 0;
3726 //*********************************************************************************
3727 // [public] settleTimerExpired
3729 // Power has settled after our last change. Notify interested parties that
3730 // there is a new power state.
3731 //*********************************************************************************
3733 void IOService::settleTimerExpired ( void )
3738 //*********************************************************************************
3739 // [private] compute_settle_time
3741 // Compute the power-settling delay in microseconds for the
3742 // change from myCurrentState to head_note_state.
3743 //*********************************************************************************
3745 unsigned long IOService::compute_settle_time ( void )
3747 unsigned long totalTime
;
3750 PM_ASSERT_IN_GATE();
3752 // compute total time to attain the new state
3754 i
= fCurrentPowerState
;
3756 // we're lowering power
3757 if ( fHeadNoteState
< fCurrentPowerState
)
3759 while ( i
> fHeadNoteState
)
3761 totalTime
+= fPowerStates
[i
].settleDownTime
;
3766 // we're raising power
3767 if ( fHeadNoteState
> fCurrentPowerState
)
3769 while ( i
< fHeadNoteState
)
3771 totalTime
+= fPowerStates
[i
+1].settleUpTime
;
3779 //*********************************************************************************
3780 // [private] startSettleTimer
3782 // Enter a power-settling delay in microseconds and start a timer for that delay.
3783 //*********************************************************************************
3785 IOReturn
IOService::startSettleTimer ( unsigned long delay
)
3787 AbsoluteTime deadline
;
3791 clock_interval_to_deadline(delay
, kMicrosecondScale
, &deadline
);
3792 pending
= thread_call_enter_delayed(fSettleTimer
, deadline
);
3793 if (pending
) release();
3798 //*********************************************************************************
3799 // [public] ackTimerTick
3801 // The acknowledgement timeout periodic timer has ticked.
3802 // If we are awaiting acks for a power change notification,
3803 // we decrement the timer word of each interested driver which hasn't acked.
3804 // If a timer word becomes zero, we pretend the driver aknowledged.
3805 // If we are waiting for the controlling driver to change the power
3806 // state of the hardware, we decrement its timer word, and if it becomes
3807 // zero, we pretend the driver acknowledged.
3809 // Returns true if the timer tick made it possible to advance to the next
3810 // machine state, false otherwise.
3811 //*********************************************************************************
3813 void IOService::ack_timer_ticked ( void )
3818 bool IOService::ackTimerTick( void )
3820 IOPMinformee
* nextObject
;
3823 PM_ASSERT_IN_GATE();
3824 switch (fMachineState
) {
3825 case kIOPM_OurChangeWaitForPowerSettle
:
3826 case kIOPM_ParentDownWaitForPowerSettle
:
3827 case kIOPM_ParentUpWaitForSettleTime
:
3828 // are we waiting for controlling driver to acknowledge?
3829 if ( fDriverTimer
> 0 )
3831 // yes, decrement timer tick
3833 if ( fDriverTimer
== 0 )
3835 // controlling driver is tardy
3836 uint64_t nsec
= computeTimeDeltaNS(&fDriverCallStartTime
);
3837 OUR_PMLog(kPMLogCtrlDriverTardy
, 0, 0);
3838 setProperty(kIOPMTardyAckSPSKey
, kOSBooleanTrue
);
3839 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
3840 fName
, this, fCurrentPowerState
, fHeadNoteState
, NS_TO_MS(nsec
));
3842 if (gIOKitDebug
& kIOLogDebugPower
)
3844 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
3845 fName
, this, fCurrentPowerState
, fHeadNoteState
, NS_TO_MS(nsec
));
3849 // Unblock state machine and pretend driver has acked.
3853 // still waiting, set timer again
3859 case kIOPM_OurChangeSetPowerState
:
3860 case kIOPM_OurChangeFinish
:
3861 case kIOPM_ParentDownSetPowerState
:
3862 case kIOPM_ParentDownAcknowledgeChange
:
3863 case kIOPM_ParentUpSetPowerState
:
3864 case kIOPM_ParentUpAcknowledgePowerChange
:
3865 case kIOPM_NotifyChildrenDone
:
3866 // are we waiting for interested parties to acknowledge?
3867 if ( fHeadNotePendingAcks
!= 0 )
3869 // yes, go through the list of interested drivers
3870 nextObject
= fInterestedDrivers
->firstInList();
3871 // and check each one
3872 while ( nextObject
!= NULL
)
3874 if ( nextObject
->timer
> 0 )
3876 nextObject
->timer
--;
3877 // this one should have acked by now
3878 if ( nextObject
->timer
== 0 )
3880 uint64_t nsec
= computeTimeDeltaNS(&nextObject
->startTime
);
3881 OUR_PMLog(kPMLogIntDriverTardy
, 0, 0);
3882 nextObject
->whatObject
->setProperty(kIOPMTardyAckPSCKey
, kOSBooleanTrue
);
3883 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
3884 nextObject
->whatObject
->getName(),
3885 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
3886 nextObject
->whatObject
, fName
, fCurrentPowerState
, fHeadNoteState
,
3889 // Pretend driver has acked.
3890 fHeadNotePendingAcks
--;
3893 nextObject
= fInterestedDrivers
->nextInList(nextObject
);
3896 // is that the last?
3897 if ( fHeadNotePendingAcks
== 0 )
3899 // yes, we can continue
3902 // no, set timer again
3908 case kIOPM_ParentDownTellPriorityClientsPowerDown
:
3909 case kIOPM_ParentDownNotifyInterestedDriversWillChange
:
3910 case kIOPM_OurChangeTellClientsPowerDown
:
3911 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
3912 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
3913 // apps didn't respond in time
3914 cleanClientResponses(true);
3915 OUR_PMLog(kPMLogClientTardy
, 0, 1);
3916 // tardy equates to approval
3921 PM_TRACE("[%s] unexpected ack timer tick (state = %ld)\n",
3922 getName(), fMachineState
);
3928 //*********************************************************************************
3929 // [private] start_ack_timer
3930 //*********************************************************************************
3932 void IOService::start_ack_timer ( void )
3934 start_ack_timer( ACK_TIMER_PERIOD
, kNanosecondScale
);
3937 void IOService::start_ack_timer ( UInt32 interval
, UInt32 scale
)
3939 AbsoluteTime deadline
;
3942 clock_interval_to_deadline(interval
, scale
, &deadline
);
3945 pending
= thread_call_enter_delayed(fAckTimer
, deadline
);
3946 if (pending
) release();
3949 //*********************************************************************************
3950 // [private] stop_ack_timer
3951 //*********************************************************************************
3953 void IOService::stop_ack_timer ( void )
3957 pending
= thread_call_cancel(fAckTimer
);
3958 if (pending
) release();
3961 //*********************************************************************************
3962 // [static] settleTimerExpired
3964 // Inside PM work loop's gate.
3965 //*********************************************************************************
3968 IOService::actionAckTimerExpired (
3970 void * arg0
, void * arg1
,
3971 void * arg2
, void * arg3
)
3973 IOService
* me
= (IOService
*) target
;
3976 // done will be true if the timer tick unblocks the machine state,
3977 // otherwise no need to signal the work loop.
3979 done
= me
->ackTimerTick();
3980 if (done
&& gIOPMReplyQueue
)
3981 gIOPMReplyQueue
->signalWorkAvailable();
3983 return kIOReturnSuccess
;
3986 //*********************************************************************************
3987 // ack_timer_expired
3989 // Thread call function. Holds a retain while the callout is in flight.
3990 //*********************************************************************************
3993 IOService::ack_timer_expired ( thread_call_param_t arg0
, thread_call_param_t arg1
)
3995 IOService
* me
= (IOService
*) arg0
;
3999 gIOPMWorkLoop
->runAction(&actionAckTimerExpired
, me
);
4004 //*********************************************************************************
4005 // settleTimerExpired
4007 // Inside PM work loop's gate.
4008 //*********************************************************************************
4011 settleTimerExpired (
4013 void * arg0
, void * arg1
,
4014 void * arg2
, void * arg3
)
4016 IOService
* me
= (IOService
*) target
;
4017 me
->settleTimerExpired();
4018 return kIOReturnSuccess
;
4021 //*********************************************************************************
4022 // settle_timer_expired
4024 // Thread call function. Holds a retain while the callout is in flight.
4025 //*********************************************************************************
4028 settle_timer_expired ( thread_call_param_t arg0
, thread_call_param_t arg1
)
4030 IOService
* me
= (IOService
*) arg0
;
4032 if (gIOPMWorkLoop
&& gIOPMReplyQueue
)
4034 gIOPMWorkLoop
->runAction(settleTimerExpired
, me
);
4035 gIOPMReplyQueue
->signalWorkAvailable();
4040 //*********************************************************************************
4041 // [private] start_parent_change
4043 // Here we begin the processing of a power change initiated by our parent.
4044 //*********************************************************************************
4046 IOReturn
IOService::start_parent_change ( const changeNoteItem
* changeNote
)
4048 fHeadNoteFlags
= changeNote
->flags
;
4049 fHeadNoteState
= changeNote
->newStateNumber
;
4050 fHeadNoteOutputFlags
= changeNote
->outputPowerCharacter
;
4051 fHeadNoteDomainState
= changeNote
->domainState
;
4052 fHeadNoteParent
= changeNote
->parent
;
4053 fHeadNoteCapabilityFlags
= changeNote
->capabilityFlags
;
4055 PM_ASSERT_IN_GATE();
4056 OUR_PMLog( kPMLogStartParentChange
, fHeadNoteState
, fCurrentPowerState
);
4058 // Power domain is lowering power
4059 if ( fHeadNoteState
< fCurrentPowerState
)
4062 changeNote
->singleParentState
,
4063 fHeadNoteParent
, true );
4065 // tell apps and kernel clients
4066 fInitialChange
= false;
4067 fMachineState
= kIOPM_ParentDownTellPriorityClientsPowerDown
;
4068 tellChangeDown1(fHeadNoteState
);
4069 return IOPMWillAckLater
;
4072 // Power domain is raising power
4073 if ( fHeadNoteState
> fCurrentPowerState
)
4075 IOPMPowerState
* powerStatePtr
;
4077 if ( fDesiredPowerState
> fCurrentPowerState
)
4079 if ( fDesiredPowerState
< fHeadNoteState
)
4081 // We power up, but not all the way
4082 fHeadNoteState
= fDesiredPowerState
;
4083 powerStatePtr
= &fPowerStates
[fHeadNoteState
];
4084 fHeadNoteOutputFlags
= powerStatePtr
->outputPowerCharacter
;
4085 fHeadNoteCapabilityFlags
= powerStatePtr
->capabilityFlags
;
4086 OUR_PMLog(kPMLogAmendParentChange
, fHeadNoteState
, 0);
4089 // We don't need to change
4090 fHeadNoteState
= fCurrentPowerState
;
4091 powerStatePtr
= &fPowerStates
[fHeadNoteState
];
4092 fHeadNoteOutputFlags
= powerStatePtr
->outputPowerCharacter
;
4093 fHeadNoteCapabilityFlags
= powerStatePtr
->capabilityFlags
;
4094 OUR_PMLog(kPMLogAmendParentChange
, fHeadNoteState
, 0);
4098 if ((fHeadNoteState
> fCurrentPowerState
) &&
4099 (fHeadNoteFlags
& IOPMDomainDidChange
))
4101 // Parent did change up - start our change up
4102 fInitialChange
= false;
4103 fMachineState
= kIOPM_ParentUpSetPowerState
;
4105 return IOPMWillAckLater
;
4109 return IOPMAckImplied
;
4112 //*********************************************************************************
4113 // [private] start_our_change
4115 // Here we begin the processing of a power change initiated by us.
4116 //*********************************************************************************
4118 void IOService::start_our_change ( const changeNoteItem
* changeNote
)
4120 fHeadNoteFlags
= changeNote
->flags
;
4121 fHeadNoteState
= changeNote
->newStateNumber
;
4122 fHeadNoteOutputFlags
= changeNote
->outputPowerCharacter
;
4123 fHeadNoteCapabilityFlags
= changeNote
->capabilityFlags
;
4125 PM_ASSERT_IN_GATE();
4127 OUR_PMLog( kPMLogStartDeviceChange
, fHeadNoteState
, fCurrentPowerState
);
4129 // can our driver switch to the new state?
4130 if (( fHeadNoteCapabilityFlags
& IOPMNotAttainable
) ||
4131 ((fMaxCapability
< fHeadNoteState
) && (!fWeAreRoot
)))
4133 // mark the change note un-actioned
4134 fHeadNoteFlags
|= IOPMNotDone
;
4136 // no, ask the parent to do it then
4139 ask_parent(fHeadNoteState
);
4145 if ( !fInitialChange
)
4147 if ( fHeadNoteState
== fCurrentPowerState
)
4149 // we initiated a null change; forget it
4154 fInitialChange
= false;
4157 if ( fHeadNoteState
< fCurrentPowerState
)
4159 // yes, in case we have to wait for acks
4160 fMachineState
= kIOPM_OurChangeTellClientsPowerDown
;
4161 fDoNotPowerDown
= false;
4163 // ask apps and kernel clients if we can drop power
4164 fOutOfBandParameter
= kNotifyApps
;
4165 askChangeDown(fHeadNoteState
);
4167 // in case they don't all ack
4168 fMachineState
= kIOPM_OurChangeSetPowerState
;
4169 // notify interested drivers and children
4174 //*********************************************************************************
4175 // [private] ask_parent
4177 // Call the power domain parent to ask for a higher power state in the domain
4178 // or to suggest a lower power state.
4179 //*********************************************************************************
4181 IOReturn
IOService::ask_parent ( unsigned long requestedState
)
4185 IOPowerConnection
* connection
;
4187 const IOPMPowerState
* powerStatePtr
;
4188 unsigned long ourRequest
;
4190 PM_ASSERT_IN_GATE();
4191 if (requestedState
>= fNumberOfPowerStates
)
4194 powerStatePtr
= &fPowerStates
[requestedState
];
4195 ourRequest
= powerStatePtr
->inputPowerRequirement
;
4197 if ( powerStatePtr
->capabilityFlags
& (kIOPMChildClamp
| kIOPMPreventIdleSleep
) )
4199 ourRequest
|= kIOPMPreventIdleSleep
;
4201 if ( powerStatePtr
->capabilityFlags
& (kIOPMChildClamp2
| kIOPMPreventSystemSleep
) )
4203 ourRequest
|= kIOPMPreventSystemSleep
;
4206 // is this a new desire?
4207 if ( fPreviousRequest
== ourRequest
)
4209 // no, the parent knows already, just return
4217 fPreviousRequest
= ourRequest
;
4219 iter
= getParentIterator(gIOPowerPlane
);
4222 while ( (next
= iter
->getNextObject()) )
4224 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
4226 parent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
4228 if ( parent
->requestPowerDomainState(
4229 ourRequest
, connection
, IOPMLowestState
) != IOPMNoErr
)
4231 OUR_PMLog(kPMLogRequestDenied
, fPreviousRequest
, 0);
4243 //*********************************************************************************
4244 // [private] notifyControllingDriver
4245 //*********************************************************************************
4247 bool IOService::notifyControllingDriver ( void )
4249 DriverCallParam
* param
;
4250 unsigned long powerState
;
4252 PM_ASSERT_IN_GATE();
4253 assert( fDriverCallBusy
== false );
4254 assert( fDriverCallParamCount
== 0 );
4255 assert( fControllingDriver
);
4257 powerState
= fHeadNoteState
;
4258 if (fPowerStates
[powerState
].capabilityFlags
& IOPMNotAttainable
)
4259 return false; // state not attainable
4261 param
= (DriverCallParam
*) fDriverCallParamPtr
;
4264 param
= IONew(DriverCallParam
, 1);
4266 return false; // no memory
4268 fDriverCallParamPtr
= (void *) param
;
4269 fDriverCallParamSlots
= 1;
4272 param
->Target
= fControllingDriver
;
4273 fDriverCallParamCount
= 1;
4277 // Machine state for this object will stall waiting for a reply
4278 // from the callout thread.
4281 fDriverCallBusy
= true;
4283 thread_call_enter( fDriverCallEntry
);
4287 //*********************************************************************************
4288 // [private] notifyControllingDriverDone
4289 //*********************************************************************************
4291 void IOService::notifyControllingDriverDone( void )
4293 DriverCallParam
* param
;
4296 PM_ASSERT_IN_GATE();
4297 param
= (DriverCallParam
*) fDriverCallParamPtr
;
4299 assert( fDriverCallBusy
== false );
4300 assert( fMachineState
== kIOPM_DriverThreadCallDone
);
4304 assert(fDriverCallParamCount
== 1);
4306 // the return value from setPowerState()
4307 result
= param
->Result
;
4309 if ((result
== IOPMAckImplied
) || (result
< 0))
4311 // child return IOPMAckImplied
4314 else if (fDriverTimer
)
4316 assert(fDriverTimer
== -1);
4318 // Driver has not acked, and has returned a positive result.
4319 // Enforce a minimum permissible timeout value.
4320 // Make the min value large enough so timeout is less likely
4321 // to occur if a driver misinterpreted that the return value
4322 // should be in microsecond units. And make it large enough
4323 // to be noticeable if a driver neglects to ack.
4325 if (result
< kMinAckTimeoutTicks
)
4326 result
= kMinAckTimeoutTicks
;
4328 fDriverTimer
= (result
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
4330 // else, child has already acked and driver_timer reset to 0.
4332 fDriverCallParamCount
= 0;
4336 OUR_PMLog(kPMLogStartAckTimer
, 0, 0);
4341 // Hop back to original machine state path.
4342 fMachineState
= fNextMachineState
;
4345 //*********************************************************************************
4346 // [public virtual] askChangeDown
4348 // Ask registered applications and kernel clients if we can change to a lower
4351 // Subclass can override this to send a different message type. Parameter is
4352 // the destination state number.
4354 // Return true if we don't have to wait for acknowledgements
4355 //*********************************************************************************
4357 bool IOService::askChangeDown ( unsigned long stateNum
)
4359 return tellClientsWithResponse( kIOMessageCanDevicePowerOff
);
4362 //*********************************************************************************
4363 // [public] tellChangeDown1
4365 // Notify registered applications and kernel clients that we are definitely
4368 // Return true if we don't have to wait for acknowledgements
4369 //*********************************************************************************
4371 bool IOService::tellChangeDown1 ( unsigned long stateNum
)
4373 fOutOfBandParameter
= kNotifyApps
;
4374 return tellChangeDown(stateNum
);
4377 //*********************************************************************************
4378 // [public] tellChangeDown2
4380 // Notify priority clients that we are definitely dropping power.
4382 // Return true if we don't have to wait for acknowledgements
4383 //*********************************************************************************
4385 bool IOService::tellChangeDown2 ( unsigned long stateNum
)
4387 fOutOfBandParameter
= kNotifyPriority
;
4388 return tellChangeDown(stateNum
);
4391 //*********************************************************************************
4392 // [public virtual] tellChangeDown
4394 // Notify registered applications and kernel clients that we are definitely
4397 // Subclass can override this to send a different message type. Parameter is
4398 // the destination state number.
4400 // Return true if we don't have to wait for acknowledgements
4401 //*********************************************************************************
4403 bool IOService::tellChangeDown ( unsigned long stateNum
)
4405 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff
);
4408 //*********************************************************************************
4409 // cleanClientResponses
4411 //*********************************************************************************
4413 static void logAppTimeouts ( OSObject
* object
, void * context
)
4415 struct context
*theContext
= (struct context
*)context
;
4418 if( !OSDynamicCast( IOService
, object
) ) {
4419 flag
= theContext
->responseFlags
->getObject(theContext
->counter
);
4420 if (kOSBooleanTrue
!= flag
)
4422 OSString
* clientID
= 0;
4423 theContext
->us
->messageClient(theContext
->msgType
, object
, &clientID
);
4424 PM_ERROR(theContext
->errorLog
, clientID
? clientID
->getCStringNoCopy() : "");
4426 clientID
->release();
4428 theContext
->counter
+= 1;
4432 void IOService::cleanClientResponses ( bool logErrors
)
4434 struct context theContext
;
4436 if (logErrors
&& fResponseArray
) {
4437 theContext
.responseFlags
= fResponseArray
;
4438 theContext
.serialNumber
= fSerialNumber
;
4439 theContext
.counter
= 0;
4440 theContext
.msgType
= kIOMessageCopyClientID
;
4441 theContext
.us
= this;
4442 theContext
.maxTimeRequested
= 0;
4443 theContext
.stateNumber
= fHeadNoteState
;
4444 theContext
.stateFlags
= fHeadNoteCapabilityFlags
;
4445 theContext
.errorLog
= "PM notification timeout (%s)\n";
4447 switch ( fOutOfBandParameter
) {
4449 applyToInterested(gIOAppPowerStateInterest
, logAppTimeouts
, (void *) &theContext
);
4450 case kNotifyPriority
:
4458 // get rid of this stuff
4459 fResponseArray
->release();
4460 fResponseArray
= NULL
;
4466 //*********************************************************************************
4467 // [public] tellClientsWithResponse
4469 // Notify registered applications and kernel clients that we are definitely
4472 // Return true if we don't have to wait for acknowledgements
4473 //*********************************************************************************
4475 bool IOService::tellClientsWithResponse ( int messageType
)
4477 struct context theContext
;
4479 PM_ASSERT_IN_GATE();
4481 fResponseArray
= OSArray::withCapacity( 1 );
4484 theContext
.responseFlags
= fResponseArray
;
4485 theContext
.serialNumber
= fSerialNumber
;
4486 theContext
.counter
= 0;
4487 theContext
.msgType
= messageType
;
4488 theContext
.us
= this;
4489 theContext
.maxTimeRequested
= 0;
4490 theContext
.stateNumber
= fHeadNoteState
;
4491 theContext
.stateFlags
= fHeadNoteCapabilityFlags
;
4493 switch ( fOutOfBandParameter
) {
4495 applyToInterested(gIOAppPowerStateInterest
,
4496 pmTellAppWithResponse
, (void *)&theContext
);
4497 applyToInterested(gIOGeneralInterest
,
4498 pmTellClientWithResponse
, (void *)&theContext
);
4500 case kNotifyPriority
:
4501 applyToInterested(gIOPriorityPowerStateInterest
,
4502 pmTellClientWithResponse
, (void *)&theContext
);
4506 // do we have to wait for somebody?
4507 if ( !checkForDone() )
4509 OUR_PMLog(kPMLogStartAckTimer
,theContext
.maxTimeRequested
, 0);
4510 start_ack_timer( theContext
.maxTimeRequested
/ 1000, kMillisecondScale
);
4514 // everybody responded
4515 fResponseArray
->release();
4516 fResponseArray
= NULL
;
4517 // cleanClientResponses(false);
4522 //*********************************************************************************
4523 // [static private] pmTellAppWithResponse
4525 // We send a message to an application, and we expect a response, so we compute a
4526 // cookie we can identify the response with.
4527 //*********************************************************************************
4529 void IOService::pmTellAppWithResponse ( OSObject
* object
, void * context
)
4531 struct context
* theContext
= (struct context
*) context
;
4532 IOServicePM
* pwrMgt
= theContext
->us
->pwrMgt
;
4535 if( OSDynamicCast( IOService
, object
) )
4537 // Automatically 'ack' in kernel clients
4538 theContext
->responseFlags
->setObject(theContext
->counter
, kOSBooleanTrue
);
4540 const char *who
= ((IOService
*) object
)->getName();
4541 fPlatform
->PMLog(who
,
4542 kPMLogClientAcknowledge
, theContext
->msgType
, * (UInt32
*) object
);
4544 UInt32 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16)
4545 + (theContext
->counter
& 0xFFFF);
4546 OUR_PMLog(kPMLogAppNotify
, theContext
->msgType
, refcon
);
4548 #if LOG_APP_RESPONSE_TIMES
4550 clock_get_uptime(&now
);
4551 num
= OSNumber::withNumber(AbsoluteTime_to_scalar(&now
), sizeof(uint64_t) * 8);
4554 theContext
->responseFlags
->setObject(theContext
->counter
, num
);
4559 theContext
->responseFlags
->setObject(theContext
->counter
, kOSBooleanFalse
);
4561 theContext
->us
->messageClient(theContext
->msgType
, object
, (void *)refcon
);
4562 if ( theContext
->maxTimeRequested
< k30seconds
)
4564 theContext
->maxTimeRequested
= k30seconds
;
4567 theContext
->counter
+= 1;
4571 //*********************************************************************************
4572 // [static private] pmTellClientWithResponse
4574 // We send a message to an in-kernel client, and we expect a response, so we compute a
4575 // cookie we can identify the response with.
4576 // If it doesn't understand the notification (it is not power-management savvy)
4577 // we won't wait for it to prepare for sleep. If it tells us via a return code
4578 // in the passed struct that it is currently ready, we won't wait for it to prepare.
4579 // If it tells us via the return code in the struct that it does need time, we will chill.
4580 //*********************************************************************************
4582 void IOService::pmTellClientWithResponse ( OSObject
* object
, void * context
)
4584 struct context
*theContext
= (struct context
*)context
;
4585 IOPowerStateChangeNotification notify
;
4590 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
4591 theContext
->responseFlags
->setObject(theContext
->counter
, kOSBooleanFalse
);
4593 IOServicePM
* pwrMgt
= theContext
->us
->pwrMgt
;
4594 if (gIOKitDebug
& kIOLogPower
) {
4595 OUR_PMLog(kPMLogClientNotify
, refcon
, (UInt32
) theContext
->msgType
);
4596 if (OSDynamicCast(IOService
, object
)) {
4597 const char *who
= ((IOService
*) object
)->getName();
4598 fPlatform
->PMLog(who
,
4599 kPMLogClientNotify
, * (UInt32
*) object
, (UInt32
) object
);
4600 } else if (OSDynamicCast(_IOServiceInterestNotifier
, object
)) {
4601 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
4602 OUR_PMLog(kPMLogClientNotify
, (UInt32
) n
->handler
, 0);
4606 notify
.powerRef
= (void *)refcon
;
4607 notify
.returnValue
= 0;
4608 notify
.stateNumber
= theContext
->stateNumber
;
4609 notify
.stateFlags
= theContext
->stateFlags
;
4610 retCode
= theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)¬ify
);
4611 if ( retCode
== kIOReturnSuccess
)
4613 if ( notify
.returnValue
== 0 )
4615 // client doesn't want time to respond
4616 theContext
->responseFlags
->replaceObject(theContext
->counter
, kOSBooleanTrue
);
4617 OUR_PMLog(kPMLogClientAcknowledge
, refcon
, (UInt32
) object
);
4619 // it does want time, and it hasn't responded yet
4620 theFlag
= theContext
->responseFlags
->getObject(theContext
->counter
);
4621 if ( kOSBooleanTrue
!= theFlag
)
4623 // so note its time requirement
4624 if ( theContext
->maxTimeRequested
< notify
.returnValue
)
4626 theContext
->maxTimeRequested
= notify
.returnValue
;
4631 OUR_PMLog(kPMLogClientAcknowledge
, refcon
, 0);
4632 // not a client of ours
4633 // so we won't be waiting for response
4634 theContext
->responseFlags
->replaceObject(theContext
->counter
, kOSBooleanTrue
);
4636 theContext
->counter
+= 1;
4639 //*********************************************************************************
4640 // [public virtual] tellNoChangeDown
4642 // Notify registered applications and kernel clients that we are not
4645 // Subclass can override this to send a different message type. Parameter is
4646 // the aborted destination state number.
4647 //*********************************************************************************
4649 void IOService::tellNoChangeDown ( unsigned long )
4651 return tellClients( kIOMessageDeviceWillNotPowerOff
);
4654 //*********************************************************************************
4655 // [public virtual] tellChangeUp
4657 // Notify registered applications and kernel clients that we are raising power.
4659 // Subclass can override this to send a different message type. Parameter is
4660 // the aborted destination state number.
4661 //*********************************************************************************
4663 void IOService::tellChangeUp ( unsigned long )
4665 return tellClients( kIOMessageDeviceHasPoweredOn
);
4668 //*********************************************************************************
4669 // [public] tellClients
4671 // Notify registered applications and kernel clients of something.
4672 //*********************************************************************************
4674 void IOService::tellClients ( int messageType
)
4676 struct context theContext
;
4678 theContext
.msgType
= messageType
;
4679 theContext
.us
= this;
4680 theContext
.stateNumber
= fHeadNoteState
;
4681 theContext
.stateFlags
= fHeadNoteCapabilityFlags
;
4683 applyToInterested(gIOPriorityPowerStateInterest
,tellClient
,(void *)&theContext
);
4684 applyToInterested(gIOAppPowerStateInterest
,tellClient
, (void *)&theContext
);
4685 applyToInterested(gIOGeneralInterest
,tellClient
, (void *)&theContext
);
4688 //*********************************************************************************
4689 // [global] tellClient
4691 // Notify a registered application or kernel client of something.
4692 //*********************************************************************************
4694 void tellClient ( OSObject
* object
, void * context
)
4696 struct context
* theContext
= (struct context
*) context
;
4697 IOPowerStateChangeNotification notify
;
4699 notify
.powerRef
= (void *) 0;
4700 notify
.returnValue
= 0;
4701 notify
.stateNumber
= theContext
->stateNumber
;
4702 notify
.stateFlags
= theContext
->stateFlags
;
4704 theContext
->us
->messageClient(theContext
->msgType
, object
, ¬ify
);
4707 //*********************************************************************************
4708 // [private] checkForDone
4709 //*********************************************************************************
4711 bool IOService::checkForDone ( void )
4716 if ( fResponseArray
== NULL
)
4721 for ( i
= 0; ; i
++ )
4723 theFlag
= fResponseArray
->getObject(i
);
4724 if ( theFlag
== NULL
)
4728 if ( kOSBooleanTrue
!= theFlag
)
4736 //*********************************************************************************
4737 // [public] responseValid
4738 //*********************************************************************************
4740 bool IOService::responseValid ( unsigned long x
, int pid
)
4742 UInt16 serialComponent
;
4743 UInt16 ordinalComponent
;
4745 unsigned long refcon
= (unsigned long) x
;
4747 serialComponent
= (refcon
>> 16) & 0xFFFF;
4748 ordinalComponent
= (refcon
& 0xFFFF);
4750 if ( serialComponent
!= fSerialNumber
)
4755 if ( fResponseArray
== NULL
)
4760 theFlag
= fResponseArray
->getObject(ordinalComponent
);
4768 if ((num
= OSDynamicCast(OSNumber
, theFlag
)))
4770 #if LOG_APP_RESPONSE_TIMES
4775 clock_get_uptime(&now
);
4776 AbsoluteTime_to_scalar(&start
) = num
->unsigned64BitValue();
4777 SUB_ABSOLUTETIME(&now
, &start
);
4778 absolutetime_to_nanoseconds(now
, &nsec
);
4781 if (nsec
> LOG_APP_RESPONSE_TIMES
)
4783 OSString
* name
= IOCopyLogNameForPID(pid
);
4784 PM_DEBUG("PM response took %d ms (%s)\n", NS_TO_MS(nsec
),
4785 name
? name
->getCStringNoCopy() : "");
4790 theFlag
= kOSBooleanFalse
;
4793 if ( kOSBooleanFalse
== theFlag
)
4795 fResponseArray
->replaceObject(ordinalComponent
, kOSBooleanTrue
);
4801 //*********************************************************************************
4802 // [public virtual] allowPowerChange
4804 // Our power state is about to lower, and we have notified applications
4805 // and kernel clients, and one of them has acknowledged. If this is the last to do
4806 // so, and all acknowledgements are positive, we continue with the power change.
4808 // We serialize this processing with timer expiration with a command gate on the
4809 // power management workloop, which the timer expiration is command gated to as well.
4810 //*********************************************************************************
4812 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
4814 IOPMRequest
* request
;
4819 return kIOReturnSuccess
;
4822 request
= acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange
);
4825 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__
);
4826 return kIOReturnNoMemory
;
4829 request
->fArg0
= (void *) refcon
;
4830 request
->fArg1
= (void *) proc_selfpid();
4831 submitPMRequest( request
);
4833 return kIOReturnSuccess
;
4836 IOReturn
serializedAllowPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
4838 // [deprecated] public
4839 return kIOReturnUnsupported
;
4842 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
4844 // [deprecated] public
4845 return kIOReturnUnsupported
;
4848 //*********************************************************************************
4849 // [public virtual] cancelPowerChange
4851 // Our power state is about to lower, and we have notified applications
4852 // and kernel clients, and one of them has vetoed the change. If this is the last
4853 // client to respond, we abandon the power change.
4855 // We serialize this processing with timer expiration with a command gate on the
4856 // power management workloop, which the timer expiration is command gated to as well.
4857 //*********************************************************************************
4859 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
4861 IOPMRequest
* request
;
4866 return kIOReturnSuccess
;
4869 OSString
* name
= IOCopyLogNameForPID(proc_selfpid());
4870 PM_ERROR("PM notification cancel (%s)\n", name
? name
->getCStringNoCopy() : "");
4874 request
= acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange
);
4877 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__
);
4878 return kIOReturnNoMemory
;
4881 request
->fArg0
= (void *) refcon
;
4882 request
->fArg1
= (void *) proc_selfpid();
4883 submitPMRequest( request
);
4885 return kIOReturnSuccess
;
4888 IOReturn
serializedCancelPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
4890 // [deprecated] public
4891 return kIOReturnUnsupported
;
4894 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
4896 // [deprecated] public
4897 return kIOReturnUnsupported
;
4901 //*********************************************************************************
4902 // c_PM_clamp_Timer_Expired (C Func)
4904 // Called when our clamp timer expires...we will call the object method.
4905 //*********************************************************************************
4907 static void c_PM_Clamp_Timer_Expired ( OSObject
* client
, IOTimerEventSource
* )
4910 ((IOService
*)client
)->PM_Clamp_Timer_Expired ();
4914 //*********************************************************************************
4915 // PM_Clamp_Timer_Expired
4917 // called when clamp timer expires...set power state to 0.
4918 //*********************************************************************************
4920 void IOService::PM_Clamp_Timer_Expired ( void )
4923 if ( ! initialized
)
4929 changePowerStateToPriv (0);
4933 //*********************************************************************************
4936 // Set to highest available power state for a minimum of duration milliseconds
4937 //*********************************************************************************
4939 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
4941 void IOService::clampPowerOn ( unsigned long duration
)
4944 changePowerStateToPriv (fNumberOfPowerStates
-1);
4946 if ( pwrMgt
->clampTimerEventSrc
== NULL
) {
4947 pwrMgt
->clampTimerEventSrc
= IOTimerEventSource::timerEventSource(this,
4948 c_PM_Clamp_Timer_Expired
);
4950 IOWorkLoop
* workLoop
= getPMworkloop ();
4952 if ( !pwrMgt
->clampTimerEventSrc
|| !workLoop
||
4953 ( workLoop
->addEventSource( pwrMgt
->clampTimerEventSrc
) != kIOReturnSuccess
) ) {
4958 pwrMgt
->clampTimerEventSrc
->setTimeout(300*USEC_PER_SEC
, USEC_PER_SEC
);
4962 //*********************************************************************************
4963 // [public virtual] setPowerState
4965 // Does nothing here. This should be implemented in a subclass driver.
4966 //*********************************************************************************
4968 IOReturn
IOService::setPowerState (
4969 unsigned long powerStateOrdinal
, IOService
* whatDevice
)
4974 //*********************************************************************************
4975 // [public virtual] maxCapabilityForDomainState
4977 // Finds the highest power state in the array whose input power
4978 // requirement is equal to the input parameter. Where a more intelligent
4979 // decision is possible, override this in the subclassed driver.
4980 //*********************************************************************************
4982 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
4986 if (fNumberOfPowerStates
== 0 )
4990 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
4992 if ( (domainState
& fPowerStates
[i
].inputPowerRequirement
) ==
4993 fPowerStates
[i
].inputPowerRequirement
)
5001 //*********************************************************************************
5002 // [public virtual] initialPowerStateForDomainState
5004 // Finds the highest power state in the array whose input power
5005 // requirement is equal to the input parameter. Where a more intelligent
5006 // decision is possible, override this in the subclassed driver.
5007 //*********************************************************************************
5009 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
5013 if (fNumberOfPowerStates
== 0 )
5017 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
5019 if ( (domainState
& fPowerStates
[i
].inputPowerRequirement
) ==
5020 fPowerStates
[i
].inputPowerRequirement
)
5028 //*********************************************************************************
5029 // [public virtual] powerStateForDomainState
5031 // Finds the highest power state in the array whose input power
5032 // requirement is equal to the input parameter. Where a more intelligent
5033 // decision is possible, override this in the subclassed driver.
5034 //*********************************************************************************
5036 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
5040 if (fNumberOfPowerStates
== 0 )
5044 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
5046 if ( (domainState
& fPowerStates
[i
].inputPowerRequirement
) ==
5047 fPowerStates
[i
].inputPowerRequirement
)
5055 //*********************************************************************************
5056 // [public virtual] didYouWakeSystem
5058 // Does nothing here. This should be implemented in a subclass driver.
5059 //*********************************************************************************
5061 bool IOService::didYouWakeSystem ( void )
5066 //*********************************************************************************
5067 // [public virtual] powerStateWillChangeTo
5069 // Does nothing here. This should be implemented in a subclass driver.
5070 //*********************************************************************************
5072 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
* )
5074 return kIOPMAckImplied
;
5077 //*********************************************************************************
5078 // [public virtual] powerStateDidChangeTo
5080 // Does nothing here. This should be implemented in a subclass driver.
5081 //*********************************************************************************
5083 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
* )
5085 return kIOPMAckImplied
;
5088 //*********************************************************************************
5089 // [public virtual] powerChangeDone
5091 // Called from PM work loop thread.
5092 // Does nothing here. This should be implemented in a subclass policy-maker.
5093 //*********************************************************************************
5095 void IOService::powerChangeDone ( unsigned long )
5099 //*********************************************************************************
5100 // [public virtual] newTemperature
5102 // Does nothing here. This should be implemented in a subclass driver.
5103 //*********************************************************************************
5105 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
5110 //*********************************************************************************
5111 // [public virtual] systemWillShutdown
5113 // System shutdown and restart notification.
5114 //*********************************************************************************
5116 void IOService::systemWillShutdown( IOOptionBits specifier
)
5118 IOPMrootDomain
* rootDomain
= IOService::getPMRootDomain();
5120 rootDomain
->acknowledgeSystemWillShutdown( this );
5123 //*********************************************************************************
5124 // [private static] acquirePMRequest
5125 //*********************************************************************************
5128 IOService::acquirePMRequest( IOService
* target
, IOOptionBits requestType
)
5130 IOPMRequest
* request
;
5134 request
= IOPMRequest::create();
5137 request
->init( target
, requestType
);
5142 //*********************************************************************************
5143 // [private static] releasePMRequest
5144 //*********************************************************************************
5146 void IOService::releasePMRequest( IOPMRequest
* request
)
5155 //*********************************************************************************
5156 // [private] submitPMRequest
5157 //*********************************************************************************
5159 void IOService::submitPMRequest( IOPMRequest
* request
)
5162 assert( gIOPMReplyQueue
);
5163 assert( gIOPMRequestQueue
);
5165 PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
5166 request
->getType(), request
,
5167 request
->getTarget(), request
->getTarget()->getName(),
5168 request
->fArg0
, request
->fArg1
, request
->fArg2
);
5170 if (request
->isReply())
5171 gIOPMReplyQueue
->queuePMRequest( request
);
5173 gIOPMRequestQueue
->queuePMRequest( request
);
5176 void IOService::submitPMRequest( IOPMRequest
** requests
, IOItemCount count
)
5179 assert( count
> 0 );
5180 assert( gIOPMRequestQueue
);
5182 for (IOItemCount i
= 0; i
< count
; i
++)
5184 IOPMRequest
* req
= requests
[i
];
5185 PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
5186 req
->getType(), req
,
5187 req
->getTarget(), req
->getTarget()->getName(),
5188 req
->fArg0
, req
->fArg1
, req
->fArg2
);
5191 gIOPMRequestQueue
->queuePMRequestChain( requests
, count
);
5194 //*********************************************************************************
5195 // [private] servicePMRequestQueue
5196 //*********************************************************************************
5198 bool IOService::servicePMRequestQueue(
5199 IOPMRequest
* request
,
5200 IOPMRequestQueue
* queue
)
5202 // Calling PM methods without PMinit() is not allowed, fail the requests.
5206 PM_DEBUG("[%s] %s: PM not initialized\n", getName(), __FUNCTION__
);
5210 // Create an IOPMWorkQueue on demand, when the initial PM request is
5215 // Allocate and attach an IOPMWorkQueue on demand to avoid taking
5216 // the work loop lock in PMinit(), which may deadlock with certain
5217 // drivers / families.
5219 fPMWorkQueue
= IOPMWorkQueue::create(
5221 /* Work */ OSMemberFunctionCast(IOPMWorkQueue::Action
, this,
5222 &IOService::servicePMRequest
),
5223 /* Done */ OSMemberFunctionCast(IOPMWorkQueue::Action
, this,
5224 &IOService::retirePMRequest
)
5228 (gIOPMWorkLoop
->addEventSource(fPMWorkQueue
) != kIOReturnSuccess
))
5230 PM_ERROR("[%s] %s: addEventSource failed\n",
5231 getName(), __FUNCTION__
);
5232 fPMWorkQueue
->release();
5238 PM_ERROR("[%s] %s: not ready (type %02lx)\n",
5239 getName(), __FUNCTION__
, request
->getType());
5244 fPMWorkQueue
->queuePMRequest(request
);
5245 return false; // do not signal more
5248 gIOPMFreeQueue
->queuePMRequest( request
);
5249 return false; // do not signal more
5252 //*********************************************************************************
5253 // [private] servicePMFreeQueue
5255 // Called by IOPMFreeQueue to recycle a completed request.
5256 //*********************************************************************************
5258 bool IOService::servicePMFreeQueue(
5259 IOPMRequest
* request
,
5260 IOPMRequestQueue
* queue
)
5262 bool more
= request
->hasParentRequest();
5263 releasePMRequest( request
);
5267 //*********************************************************************************
5268 // [private] retirePMRequest
5270 // Called by IOPMWorkQueue to retire a completed request.
5271 //*********************************************************************************
5273 bool IOService::retirePMRequest( IOPMRequest
* request
, IOPMWorkQueue
* queue
)
5275 assert(request
&& queue
);
5277 PM_TRACE("[- %02lx] %p [%p %s] State %ld, Busy %ld\n",
5278 request
->getType(), request
, this, getName(),
5279 fMachineState
, gIOPMBusyCount
);
5281 // Catch requests created by PM_idle_timer_expiration().
5283 if ((request
->getType() == kIOPMRequestTypeActivityTickle
) &&
5284 (request
->fArg1
== (void *) false))
5286 // Idle timer power drop request completed.
5287 // Restart the idle timer if deviceDesire can go lower, otherwise set
5288 // a flag so we know to restart idle timer when deviceDesire goes up.
5290 if (fDeviceDesire
> 0)
5291 start_PM_idle_timer();
5293 fActivityTimerStopped
= true;
5296 gIOPMFreeQueue
->queuePMRequest( request
);
5300 //*********************************************************************************
5301 // [private] isPMBlocked
5303 // Check if machine state transition is blocked.
5304 //*********************************************************************************
5306 bool IOService::isPMBlocked ( IOPMRequest
* request
, int count
)
5311 if (kIOPM_Finished
== fMachineState
)
5314 if (kIOPM_DriverThreadCallDone
== fMachineState
)
5316 // 5 = kDriverCallInformPreChange
5317 // 6 = kDriverCallInformPostChange
5318 // 7 = kDriverCallSetPowerState
5319 if (fDriverCallBusy
) reason
= 5 + fDriverCallReason
;
5323 // Waiting on driver's setPowerState() timeout.
5329 // Child or interested driver acks pending.
5330 if (fHeadNotePendingAcks
)
5335 // Waiting on apps or priority power interest clients.
5341 // Waiting on settle timer expiration.
5348 fWaitReason
= reason
;
5354 PM_TRACE("[B %02lx] %p [%p %s] State %ld, Reason %d\n",
5355 request
->getType(), request
, this, getName(),
5356 fMachineState
, reason
);
5365 //*********************************************************************************
5366 // [private] servicePMRequest
5368 // Service a request from our work queue.
5369 //*********************************************************************************
5371 bool IOService::servicePMRequest( IOPMRequest
* request
, IOPMWorkQueue
* queue
)
5376 assert(request
&& queue
);
5378 while (isPMBlocked(request
, loop
++) == false)
5380 PM_TRACE("[W %02lx] %p [%p %s] State %ld\n",
5381 request
->getType(), request
, this, getName(), fMachineState
);
5383 fPMRequest
= request
;
5385 // Every PM machine states must be handled in one of the cases below.
5387 switch ( fMachineState
)
5389 case kIOPM_Finished
:
5390 executePMRequest( request
);
5393 case kIOPM_OurChangeTellClientsPowerDown
:
5394 // our change, was it vetoed?
5395 if (!fDoNotPowerDown
)
5397 // no, we can continue
5398 OurChangeTellClientsPowerDown();
5402 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
5403 PM_ERROR("%s: idle cancel\n", fName
);
5404 // yes, rescind the warning
5405 tellNoChangeDown(fHeadNoteState
);
5406 // mark the change note un-actioned
5407 fHeadNoteFlags
|= IOPMNotDone
;
5413 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
5414 // our change, should it be acted on still?
5415 #if SUPPORT_IDLE_CANCEL
5416 if (fDoNotPowerDown
)
5418 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
5419 PM_ERROR("%s: idle revert\n", fName
);
5420 // no, tell clients we're back in the old state
5421 tellChangeUp(fCurrentPowerState
);
5422 // mark the change note un-actioned
5423 fHeadNoteFlags
|= IOPMNotDone
;
5430 // yes, we can continue
5431 OurChangeTellPriorityClientsPowerDown();
5435 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
5436 OurChangeNotifyInterestedDriversWillChange();
5439 case kIOPM_OurChangeSetPowerState
:
5440 OurChangeSetPowerState();
5443 case kIOPM_OurChangeWaitForPowerSettle
:
5444 OurChangeWaitForPowerSettle();
5447 case kIOPM_OurChangeNotifyInterestedDriversDidChange
:
5448 OurChangeNotifyInterestedDriversDidChange();
5451 case kIOPM_OurChangeFinish
:
5455 case kIOPM_ParentDownTellPriorityClientsPowerDown
:
5456 ParentDownTellPriorityClientsPowerDown();
5459 case kIOPM_ParentDownNotifyInterestedDriversWillChange
:
5460 ParentDownNotifyInterestedDriversWillChange();
5463 case kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange
:
5464 ParentDownNotifyDidChangeAndAcknowledgeChange();
5467 case kIOPM_ParentDownSetPowerState
:
5468 ParentDownSetPowerState();
5471 case kIOPM_ParentDownWaitForPowerSettle
:
5472 ParentDownWaitForPowerSettle();
5475 case kIOPM_ParentDownAcknowledgeChange
:
5476 ParentDownAcknowledgeChange();
5479 case kIOPM_ParentUpSetPowerState
:
5480 ParentUpSetPowerState();
5483 case kIOPM_ParentUpWaitForSettleTime
:
5484 ParentUpWaitForSettleTime();
5487 case kIOPM_ParentUpNotifyInterestedDriversDidChange
:
5488 ParentUpNotifyInterestedDriversDidChange();
5491 case kIOPM_ParentUpAcknowledgePowerChange
:
5492 ParentUpAcknowledgePowerChange();
5495 case kIOPM_DriverThreadCallDone
:
5496 if (fDriverCallReason
== kDriverCallSetPowerState
)
5497 notifyControllingDriverDone();
5499 notifyInterestedDriversDone();
5502 case kIOPM_NotifyChildrenDone
:
5503 notifyChildrenDone();
5507 IOPanic("servicePMWorkQueue: unknown machine state");
5512 if (fMachineState
== kIOPM_Finished
)
5514 //PM_TRACE("[%s] PM End: Request %p (type %02lx)\n",
5515 // getName(), request, request->getType());
5524 //*********************************************************************************
5525 // [private] executePMRequest
5526 //*********************************************************************************
5528 void IOService::executePMRequest( IOPMRequest
* request
)
5530 assert( kIOPM_Finished
== fMachineState
);
5532 switch (request
->getType())
5534 case kIOPMRequestTypePMStop
:
5535 handlePMstop( request
);
5538 case kIOPMRequestTypeAddPowerChild1
:
5539 addPowerChild1( request
);
5542 case kIOPMRequestTypeAddPowerChild2
:
5543 addPowerChild2( request
);
5546 case kIOPMRequestTypeAddPowerChild3
:
5547 addPowerChild3( request
);
5550 case kIOPMRequestTypeRegisterPowerDriver
:
5551 handleRegisterPowerDriver( request
);
5554 case kIOPMRequestTypeAdjustPowerState
:
5558 case kIOPMRequestTypeMakeUsable
:
5559 handleMakeUsable( request
);
5562 case kIOPMRequestTypeTemporaryPowerClamp
:
5564 handleMakeUsable( request
);
5567 case kIOPMRequestTypePowerDomainWillChange
:
5568 handlePowerDomainWillChangeTo( request
);
5571 case kIOPMRequestTypePowerDomainDidChange
:
5572 handlePowerDomainDidChangeTo( request
);
5575 case kIOPMRequestTypeChangePowerStateTo
:
5576 handleChangePowerStateTo( request
);
5579 case kIOPMRequestTypeChangePowerStateToPriv
:
5580 handleChangePowerStateToPriv( request
);
5583 case kIOPMRequestTypePowerOverrideOnPriv
:
5584 case kIOPMRequestTypePowerOverrideOffPriv
:
5585 handlePowerOverrideChanged( request
);
5588 case kIOPMRequestTypeActivityTickle
:
5591 bool setDeviceDesire
= false;
5595 // Power rise from activity tickle.
5596 unsigned long ticklePowerState
= (unsigned long) request
->fArg0
;
5597 if ((fDeviceDesire
< ticklePowerState
) &&
5598 (ticklePowerState
< fNumberOfPowerStates
))
5600 setDeviceDesire
= true;
5601 fIdleTimerMinPowerState
= ticklePowerState
;
5604 else if (fDeviceDesire
> fIdleTimerMinPowerState
)
5606 // Power drop from idle timer expiration.
5607 request
->fArg0
= (void *) (fDeviceDesire
- 1);
5608 setDeviceDesire
= true;
5611 if (setDeviceDesire
)
5613 // handleChangePowerStateToPriv() does not check the
5614 // request type, as long as the args are appropriate
5615 // for kIOPMRequestTypeChangePowerStateToPriv.
5617 request
->fArg1
= (void *) false;
5618 handleChangePowerStateToPriv( request
);
5624 IOPanic("executePMRequest: unknown request type");
5628 //*********************************************************************************
5629 // [private] servicePMReplyQueue
5630 //*********************************************************************************
5632 bool IOService::servicePMReplyQueue( IOPMRequest
* request
, IOPMRequestQueue
* queue
)
5636 assert( request
&& queue
);
5637 assert( request
->isReply() );
5639 PM_TRACE("[A %02lx] %p [%p %s] State %ld\n",
5640 request
->getType(), request
, this, getName(), fMachineState
);
5642 switch ( request
->getType() )
5644 case kIOPMRequestTypeAllowPowerChange
:
5645 case kIOPMRequestTypeCancelPowerChange
:
5646 // Check if we are expecting this response.
5647 if (responseValid((unsigned long) request
->fArg0
, (int) request
->fArg1
))
5649 if (kIOPMRequestTypeCancelPowerChange
== request
->getType())
5650 fDoNotPowerDown
= true;
5655 if ( fResponseArray
)
5657 fResponseArray
->release();
5658 fResponseArray
= NULL
;
5665 case kIOPMRequestTypeAckPowerChange
:
5666 more
= handleAcknowledgePowerChange( request
);
5669 case kIOPMRequestTypeAckSetPowerState
:
5670 if (fDriverTimer
== -1)
5672 // driver acked while setPowerState() call is in-flight.
5673 // take this ack, return value from setPowerState() is irrelevant.
5674 OUR_PMLog(kPMLogDriverAcknowledgeSet
,
5675 (UInt32
) this, fDriverTimer
);
5678 else if (fDriverTimer
> 0)
5680 // expected ack, stop the timer
5683 #if LOG_SETPOWER_TIMES
5684 uint64_t nsec
= computeTimeDeltaNS(&fDriverCallStartTime
);
5685 if (nsec
> LOG_SETPOWER_TIMES
)
5686 PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
5687 fName
, this, fCurrentPowerState
, fHeadNoteState
, NS_TO_MS(nsec
));
5689 OUR_PMLog(kPMLogDriverAcknowledgeSet
, (UInt32
) this, fDriverTimer
);
5696 OUR_PMLog(kPMLogAcknowledgeErr4
, (UInt32
) this, 0);
5700 case kIOPMRequestTypeInterestChanged
:
5701 handleInterestChanged( request
);
5705 #if SUPPORT_IDLE_CANCEL
5706 case kIOPMRequestTypeIdleCancel
:
5707 if ((fMachineState
== kIOPM_OurChangeTellClientsPowerDown
)
5708 || (fMachineState
== kIOPM_OurChangeTellPriorityClientsPowerDown
))
5710 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, 0);
5711 fDoNotPowerDown
= true;
5712 if (fMachineState
== kIOPM_OurChangeTellPriorityClientsPowerDown
)
5713 cleanClientResponses(false);
5720 IOPanic("servicePMReplyQueue: unknown reply type");
5723 releasePMRequest( request
);
5727 //*********************************************************************************
5728 // IOPMRequest Class
5730 // Requests from PM clients, and also used for inter-object messaging within PM.
5731 //*********************************************************************************
5733 OSDefineMetaClassAndStructors( IOPMRequest
, IOCommand
);
5735 IOPMRequest
* IOPMRequest::create( void )
5737 IOPMRequest
* me
= OSTypeAlloc(IOPMRequest
);
5738 if (me
&& !me
->init(0, kIOPMRequestTypeInvalid
))
5746 bool IOPMRequest::init( IOService
* target
, IOOptionBits type
)
5748 if (!IOCommand::init())
5755 fArg0
= fArg1
= fArg2
= 0;
5763 void IOPMRequest::reset( void )
5765 assert( fChildCount
== 0 );
5767 fType
= kIOPMRequestTypeInvalid
;
5771 fParent
->fChildCount
--;
5782 //*********************************************************************************
5783 // IOPMRequestQueue Class
5785 // Global queues. As PM-aware drivers load and unload, their IOPMWorkQueue's are
5786 // created and deallocated. IOPMRequestQueue are created once and never released.
5787 //*********************************************************************************
5789 OSDefineMetaClassAndStructors( IOPMRequestQueue
, IOEventSource
);
5791 IOPMRequestQueue
* IOPMRequestQueue::create( IOService
* inOwner
, Action inAction
)
5793 IOPMRequestQueue
* me
= OSTypeAlloc(IOPMRequestQueue
);
5794 if (me
&& !me
->init(inOwner
, inAction
))
5802 bool IOPMRequestQueue::init( IOService
* inOwner
, Action inAction
)
5804 if (!inAction
|| !IOEventSource::init(inOwner
, (IOEventSourceAction
)inAction
))
5807 queue_init(&fQueue
);
5808 fLock
= IOLockAlloc();
5809 return (fLock
!= 0);
5812 void IOPMRequestQueue::free( void )
5819 return IOEventSource::free();
5822 void IOPMRequestQueue::queuePMRequest( IOPMRequest
* request
)
5826 queue_enter(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
5827 IOLockUnlock(fLock
);
5828 if (workLoop
) signalWorkAvailable();
5832 IOPMRequestQueue::queuePMRequestChain( IOPMRequest
** requests
, IOItemCount count
)
5836 assert(requests
&& count
);
5842 queue_enter(&fQueue
, next
, IOPMRequest
*, fCommandChain
);
5844 IOLockUnlock(fLock
);
5845 if (workLoop
) signalWorkAvailable();
5848 bool IOPMRequestQueue::checkForWork( void )
5850 Action dqAction
= (Action
) action
;
5851 IOPMRequest
* request
;
5855 IOLockLock( fLock
);
5857 while (!queue_empty(&fQueue
))
5859 queue_remove_first( &fQueue
, request
, IOPMRequest
*, fCommandChain
);
5860 IOLockUnlock( fLock
);
5861 target
= request
->getTarget();
5863 more
|= (*dqAction
)( target
, request
, this );
5864 IOLockLock( fLock
);
5867 IOLockUnlock( fLock
);
5871 void IOPMRequestQueue::signalWorkAvailable( void )
5873 IOEventSource::signalWorkAvailable();
5876 //*********************************************************************************
5877 // IOPMWorkQueue Class
5879 // Every object in the power plane that has handled a PM request, will have an
5880 // instance of IOPMWorkQueue allocated for it.
5881 //*********************************************************************************
5883 OSDefineMetaClassAndStructors( IOPMWorkQueue
, IOEventSource
);
5886 IOPMWorkQueue::create( IOService
* inOwner
, Action work
, Action retire
)
5888 IOPMWorkQueue
* me
= OSTypeAlloc(IOPMWorkQueue
);
5889 if (me
&& !me
->init(inOwner
, work
, retire
))
5897 bool IOPMWorkQueue::init( IOService
* inOwner
, Action work
, Action retire
)
5899 if (!work
|| !retire
||
5900 !IOEventSource::init(inOwner
, (IOEventSourceAction
)0))
5903 queue_init(&fWorkQueue
);
5906 fRetireAction
= retire
;
5911 void IOPMWorkQueue::queuePMRequest( IOPMRequest
* request
)
5914 assert( onThread() );
5917 queue_enter(&fWorkQueue
, request
, IOPMRequest
*, fCommandChain
);
5921 bool IOPMWorkQueue::checkForWork( void )
5923 IOPMRequest
* request
;
5924 IOService
* target
= (IOService
*) owner
;
5927 while (!queue_empty(&fWorkQueue
))
5929 request
= (IOPMRequest
*) queue_first(&fWorkQueue
);
5930 assert(request
->getTarget() == target
);
5931 if (request
->hasChildRequest()) break;
5932 done
= (*fWorkAction
)( target
, request
, this );
5935 assert(gIOPMBusyCount
> 0);
5936 if (gIOPMBusyCount
) gIOPMBusyCount
--;
5937 queue_remove_first(&fWorkQueue
, request
, IOPMRequest
*, fCommandChain
);
5938 (*fRetireAction
)( target
, request
, this );
5944 OSDefineMetaClassAndStructors(IOServicePM
, OSObject
)
5946 //*********************************************************************************
5949 // Serialize IOServicePM for debugging.
5950 //*********************************************************************************
5953 setPMProperty( OSDictionary
* dict
, const char * key
, unsigned long value
)
5955 OSNumber
* num
= OSNumber::withNumber(value
, sizeof(value
) * 8);
5958 dict
->setObject(key
, num
);
5963 bool IOServicePM::serialize( OSSerialize
* s
) const
5965 OSDictionary
* dict
;
5968 dict
= OSDictionary::withCapacity(8);
5971 setPMProperty( dict
, "CurrentPowerState", CurrentPowerState
);
5972 if (DesiredPowerState
!= CurrentPowerState
)
5973 setPMProperty( dict
, "DesiredPowerState", DesiredPowerState
);
5974 if (kIOPM_Finished
!= MachineState
)
5975 setPMProperty( dict
, "MachineState", MachineState
);
5977 setPMProperty( dict
, "ChildrenPowerState", ChildrenDesire
);
5979 setPMProperty( dict
, "DeviceChangePowerState", DeviceDesire
);
5981 setPMProperty( dict
, "DriverChangePowerState", DriverDesire
);
5982 if (DeviceOverrides
)
5983 dict
->setObject( "PowerOverrideOn", kOSBooleanTrue
);
5985 ok
= dict
->serialize(s
);