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))
120 //*********************************************************************************
122 //*********************************************************************************
125 kIOPM_OurChangeTellClientsPowerDown
= 1,
126 kIOPM_OurChangeTellPriorityClientsPowerDown
= 2,
127 kIOPM_OurChangeNotifyInterestedDriversWillChange
= 3,
128 kIOPM_OurChangeSetPowerState
= 4,
129 kIOPM_OurChangeWaitForPowerSettle
= 5,
130 kIOPM_OurChangeNotifyInterestedDriversDidChange
= 6,
131 kIOPM_OurChangeFinish
= 7,
132 kIOPM_ParentDownTellPriorityClientsPowerDown
= 8,
133 kIOPM_ParentDownNotifyInterestedDriversWillChange
= 9,
135 kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange
= 11,
136 kIOPM_ParentDownSetPowerState
= 12,
137 kIOPM_ParentDownWaitForPowerSettle
= 13,
138 kIOPM_ParentDownAcknowledgeChange
= 14,
139 kIOPM_ParentUpSetPowerState
= 15,
141 kIOPM_ParentUpWaitForSettleTime
= 17,
142 kIOPM_ParentUpNotifyInterestedDriversDidChange
= 18,
143 kIOPM_ParentUpAcknowledgePowerChange
= 19,
145 kIOPM_DriverThreadCallDone
= 21,
146 kIOPM_NotifyChildrenDone
= 22
151 Power Management defines a few roles that drivers can play in their own,
152 and other drivers', power management. We briefly define those here.
154 Many drivers implement their policy maker and power controller within the same
155 IOService object, but that is not required.
158 * Virtual IOService PM methods a "policy maker" may implement
159 * maxCapabilityForDomainState()
160 * initialPowerStateForDomainState()
161 * powerStateForDomainState()
163 * Virtual IOService PM methods a "policy maker" may CALL
166 == Power Controller ==
167 * Virtual IOService PM methods a "power controller" may implement
170 * Virtual IOService PM methods a "power controller" may CALL
172 * registerPowerDriver()
174 =======================
175 There are two different kinds of power state changes.
176 * One is initiated by a subclassed device object which has either decided
177 to change power state, or its controlling driver has suggested it, or
178 some other driver wants to use the idle device and has asked it to become
180 * The second kind of power state change is initiated by the power domain
182 The two are handled through different code paths.
184 We maintain a queue of "change notifications," or change notes.
185 * Usually the queue is empty.
186 * When it isn't, usually there is one change note in it
187 * It's possible to have more than one power state change pending at one
188 time, so a queue is implemented.
190 * The subclass device decides it's idle and initiates a change to a lower
191 power state. This causes interested parties to be notified, but they
192 don't all acknowledge right away. This causes the change note to sit
193 in the queue until all the acks are received. During this time, the
194 device decides it isn't idle anymore and wants to raise power back up
195 again. This change can't be started, however, because the previous one
196 isn't complete yet, so the second one waits in the queue. During this
197 time, the parent decides to lower or raise the power state of the entire
198 power domain and notifies the device, and that notification goes into
199 the queue, too, and can't be actioned until the others are.
202 This is how a power change initiated by the subclass device is handled:
203 -> First, all interested parties are notified of the change via their
204 powerStateWillChangeTo method. If they all don't acknowledge via return
205 code, then we have to wait. If they do, or when they finally all
206 acknowledge via our acknowledgePowerChange method, then we can continue.
207 -> We call the controlling driver, instructing it to change to the new state
208 -> Then we wait for power to settle. If there is no settling-time, or after
210 -> we notify interested parties again, this time via their
211 powerStateDidChangeTo methods.
212 -> When they have all acked, we're done.
213 If we lowered power and don't need the power domain to be in its current power
214 state, we suggest to the parent that it lower the power domain state.
216 == PowerDomainDownInitiated ==
217 How a change to a lower power domain state initiated by the parent is handled:
218 -> First, we figure out what power state we will be in when the new domain
220 -> Then all interested parties are notified that we are moving to that new
222 -> When they have acknowledged, we call the controlling driver to assume
223 that state and we wait for power to settle.
224 -> Then we acknowledge our preparedness to our parent. When all its
225 interested parties have acknowledged,
226 -> it lowers power and then notifies its interested parties again.
227 -> When we get this call, we notify our interested parties that the power
228 state has changed, and when they have all acknowledged, we're done.
230 == PowerDomainUpInitiated ==
231 How a change to a higher power domain state initiated by the parent is handled:
232 -> We figure out what power state we will be in when the new domain state is
234 -> If it is different from our current state we acknowledge the parent.
235 -> When all the parent's interested parties have acknowledged, it raises
236 power in the domain and waits for power to settle.
237 -> Then it notifies everyone that the new state has been reached.
238 -> When we get this call, we call the controlling driver, instructing it to
239 assume the new state, and wait for power to settle.
240 -> Then we notify our interested parties. When they all acknowledge we are
243 In either of the two power domain state cases above, it is possible that we
244 will not be changing state even though the domain is.
246 * A change to a lower domain state may not affect us because we are already
247 in a low enough state,
248 * We will not take advantage of a change to a higher domain state, because
249 we have no need of the higher power. In such cases, there is nothing to
250 do but acknowledge the parent. So when the parent calls our
251 powerDomainWillChange method, and we decide that we will not be changing
252 state, we merely acknowledge the parent, via return code, and wait.
253 When the parent subsequently calls powerStateDidChange, we acknowledge again
254 via return code, and the change is complete.
256 == 4 Paths Through State Machine ==
257 Power state changes are processed in a state machine, and since there are four
258 varieties of power state changes, there are four major paths through the state
261 == 5. No Need To change ==
262 The fourth is nearly trivial. In this path, the parent is changing the domain
263 state, but we are not changing the device state. The change starts when the
264 parent calls powerDomainWillChange. All we do is acknowledge the parent. When
265 the parent calls powerStateDidChange, we acknowledge the parent again, and
268 == 1. OurChange Down == XXX gvdl
269 The first is fairly simple. It starts:
270 * when a power domain child calls requestPowerDomainState and we decide to
271 change power states to accomodate the child,
272 * or if our power-controlling driver calls changePowerStateTo,
273 * or if some other driver which is using our device calls makeUsable,
274 * or if a subclassed object calls changePowerStateToPriv.
275 These are all power changes initiated by us, not forced upon us by the parent.
277 -> We start by notifying interested parties.
278 -> If they all acknowledge via return code, we can go on to state
280 -> Otherwise, we start the ack timer and wait for the stragglers to
281 acknowlege by calling acknowledgePowerChange.
282 -> We move on to state "msSetPowerState" when all the
283 stragglers have acknowledged, or when the ack timer expires on
284 all those which didn't acknowledge.
285 In "msSetPowerState" we call the power-controlling driver to change the
286 power state of the hardware.
287 -> If it returns saying it has done so, we go on to state
288 "msWaitForPowerSettle".
289 -> Otherwise, we have to wait for it, so we set the ack timer and wait.
290 -> When it calls acknowledgeSetPowerState, or when the ack timer
292 In "msWaitForPowerSettle", we look in the power state array to see if
293 there is any settle time required when changing from our current state to the
295 -> If not, we go right away to "msNotifyInterestedDriversDidChange".
296 -> Otherwise, we set the settle timer and wait. When it expires, we move on.
297 In "msNotifyInterestedDriversDidChange" state, we notify all our
298 interested parties via their powerStateDidChange methods that we have finished
299 changing power state.
300 -> If they all acknowledge via return code, we move on to "msFinish".
301 -> Otherwise we set the ack timer and wait. When they have all
302 acknowledged, or when the ack timer has expired for those that didn't,
303 we move on to "msFinish".
304 In "msFinish" we remove the used change note from the head of the queue
305 and start the next one if one exists.
307 == 2. Parent Change Down ==
308 Start at Stage 2 of OurChange Down XXX gvdl
311 Start at Stage 4 of OurChange Down XXX gvdl
313 Note all parent requested changes need to acknowledge the power has changed to the parent when done.
316 //*********************************************************************************
317 // [public virtual] PMinit
319 // Initialize power management.
320 //*********************************************************************************
322 void IOService::PMinit ( void )
326 if ( !gIOPMInitialized
)
328 gIOPMWorkLoop
= IOWorkLoop::workLoop();
331 gIOPMRequestQueue
= IOPMRequestQueue::create(
332 this, OSMemberFunctionCast(IOPMRequestQueue::Action
,
333 this, &IOService::servicePMRequestQueue
));
335 gIOPMReplyQueue
= IOPMRequestQueue::create(
336 this, OSMemberFunctionCast(IOPMRequestQueue::Action
,
337 this, &IOService::servicePMReplyQueue
));
339 gIOPMFreeQueue
= IOPMRequestQueue::create(
340 this, OSMemberFunctionCast(IOPMRequestQueue::Action
,
341 this, &IOService::servicePMFreeQueue
));
343 if (gIOPMWorkLoop
->addEventSource(gIOPMRequestQueue
) !=
346 gIOPMRequestQueue
->release();
347 gIOPMRequestQueue
= 0;
350 if (gIOPMWorkLoop
->addEventSource(gIOPMReplyQueue
) !=
353 gIOPMReplyQueue
->release();
357 if (gIOPMWorkLoop
->addEventSource(gIOPMFreeQueue
) !=
360 gIOPMFreeQueue
->release();
365 if (gIOPMRequestQueue
&& gIOPMReplyQueue
&& gIOPMFreeQueue
)
366 gIOPMInitialized
= true;
368 if (!gIOPMInitialized
)
371 pwrMgt
= new IOServicePM
;
373 setProperty(kPwrMgtKey
, pwrMgt
);
377 fPMLock
= IOLockAlloc();
378 fInterestedDrivers
= new IOPMinformeeList
;
379 fInterestedDrivers
->initialize();
380 fDesiredPowerState
= 0;
383 fInitialChange
= true;
384 fNeedToBecomeUsable
= false;
385 fPreviousRequest
= 0;
386 fDeviceOverrides
= false;
387 fMachineState
= kIOPM_Finished
;
388 fIdleTimerEventSource
= NULL
;
389 fActivityLock
= IOLockAlloc();
391 fStrictTreeOrder
= false;
392 fActivityTicklePowerState
= -1;
393 fControllingDriver
= NULL
;
395 fNumberOfPowerStates
= 0;
396 fCurrentPowerState
= 0;
397 fParentsCurrentPowerFlags
= 0;
400 fPlatform
= getPlatform();
401 fParentsKnowState
= false;
403 fResponseArray
= NULL
;
404 fDoNotPowerDown
= true;
405 fCurrentPowerConsumption
= kIOPMUnknown
;
407 for (unsigned int i
= 0; i
<= kMaxType
; i
++)
409 fAggressivenessValue
[i
] = 0;
410 fAggressivenessValid
[i
] = false;
413 fAckTimer
= thread_call_allocate(
414 &IOService::ack_timer_expired
, (thread_call_param_t
)this);
415 fSettleTimer
= thread_call_allocate(
416 &settle_timer_expired
, (thread_call_param_t
)this);
417 fDriverCallEntry
= thread_call_allocate(
418 (thread_call_func_t
) &IOService::pmDriverCallout
, this);
419 assert(fDriverCallEntry
);
422 IOPMprot
* prot
= new IOPMprot
;
426 prot
->ourName
= fName
;
427 prot
->thePlatform
= fPlatform
;
432 pm_vars
= (IOPMprot
*) true;
439 //*********************************************************************************
442 // Free up the data created in PMinit, if it exists.
443 //*********************************************************************************
445 void IOService::PMfree ( void )
452 assert(fMachineState
== kIOPM_Finished
);
453 assert(fInsertInterestSet
== NULL
);
454 assert(fRemoveInterestSet
== NULL
);
455 assert(fNotifyChildArray
== NULL
);
457 if ( fIdleTimerEventSource
!= NULL
) {
458 getPMworkloop()->removeEventSource(fIdleTimerEventSource
);
459 fIdleTimerEventSource
->release();
460 fIdleTimerEventSource
= NULL
;
462 if ( fSettleTimer
) {
463 thread_call_cancel(fSettleTimer
);
464 thread_call_free(fSettleTimer
);
468 thread_call_cancel(fAckTimer
);
469 thread_call_free(fAckTimer
);
472 if ( fDriverCallEntry
) {
473 thread_call_free(fDriverCallEntry
);
474 fDriverCallEntry
= NULL
;
480 if ( fActivityLock
) {
481 IOLockFree(fActivityLock
);
482 fActivityLock
= NULL
;
484 if ( fInterestedDrivers
) {
485 fInterestedDrivers
->release();
486 fInterestedDrivers
= NULL
;
488 if ( fPMWorkQueue
) {
489 getPMworkloop()->removeEventSource(fPMWorkQueue
);
490 fPMWorkQueue
->release();
493 if (fDriverCallParamSlots
&& fDriverCallParamPtr
) {
494 IODelete(fDriverCallParamPtr
, DriverCallParam
, fDriverCallParamSlots
);
495 fDriverCallParamPtr
= 0;
496 fDriverCallParamSlots
= 0;
498 if ( fResponseArray
) {
499 fResponseArray
->release();
500 fResponseArray
= NULL
;
502 if (fPowerStates
&& fNumberOfPowerStates
) {
503 IODelete(fPowerStates
, IOPMPowerState
, fNumberOfPowerStates
);
504 fNumberOfPowerStates
= 0;
521 //*********************************************************************************
522 // [public virtual] joinPMtree
524 // A policy-maker calls its nub here when initializing, to be attached into
525 // the power management hierarchy. The default function is to call the
526 // platform expert, which knows how to do it. This method is overridden
527 // by a nub subclass which may either know how to do it, or may need to
528 // take other action.
530 // This may be the only "power management" method used in a nub,
531 // meaning it may not be initialized for power management.
532 //*********************************************************************************
534 void IOService::joinPMtree ( IOService
* driver
)
536 IOPlatformExpert
* platform
;
538 platform
= getPlatform();
539 assert(platform
!= 0);
540 platform
->PMRegisterDevice(this, driver
);
543 //*********************************************************************************
544 // [public virtual] youAreRoot
546 // Power Managment is informing us that we are the root power domain.
547 // The only difference between us and any other power domain is that
548 // we have no parent and therefore never call it.
549 //*********************************************************************************
551 IOReturn
IOService::youAreRoot ( void )
554 fParentsKnowState
= true;
555 attachToParent( getRegistryRoot(), gIOPowerPlane
);
559 //*********************************************************************************
560 // [public virtual] PMstop
562 // Immediately stop driver callouts. Schedule an async stop request to detach
564 //*********************************************************************************
566 void IOService::PMstop ( void )
568 IOPMRequest
* request
;
573 // Schedule an async PMstop request, but immediately stop any further
574 // calls to the controlling or interested drivers. This device will
575 // continue to exist in the power plane and participate in power state
576 // changes until the PMstop async request is processed.
581 PM_DEBUG("%s::PMstop() driver call busy\n", getName());
584 request
= acquirePMRequest( this, kIOPMRequestTypePMStop
);
587 PM_TRACE("[%s] %p PMstop\n", getName(), this);
588 submitPMRequest( request
);
592 //*********************************************************************************
595 // Disconnect the node from its parents and children in the Power Plane.
596 //*********************************************************************************
598 void IOService::handlePMstop ( IOPMRequest
* request
)
602 IOPowerConnection
* connection
;
603 IOService
* theChild
;
604 IOService
* theParent
;
607 PM_TRACE("[%s] %p %s start\n", getName(), this, __FUNCTION__
);
609 // remove the property
610 removeProperty(kPwrMgtKey
);
613 iter
= getParentIterator(gIOPowerPlane
);
616 while ( (next
= iter
->getNextObject()) )
618 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
620 theParent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
623 theParent
->removePowerChild(connection
);
624 theParent
->release();
631 // detach IOConnections
632 detachAbove( gIOPowerPlane
);
634 // no more power state changes
635 fParentsKnowState
= false;
638 iter
= getChildIterator(gIOPowerPlane
);
641 while ( (next
= iter
->getNextObject()) )
643 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
645 theChild
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
648 // detach nub from child
649 connection
->detachFromChild(theChild
, gIOPowerPlane
);
652 // detach us from nub
653 detachFromChild(connection
, gIOPowerPlane
);
659 // Remove all interested drivers from the list, including the power
660 // controlling driver.
662 // Usually, the controlling driver and the policy-maker functionality
663 // are implemented by the same object, and without the deregistration,
664 // the object will be holding an extra retain on itself, and cannot
667 if ( fInterestedDrivers
)
669 IOPMinformeeList
* list
= fInterestedDrivers
;
673 while ((item
= list
->firstInList()))
675 list
->removeFromList(item
->whatObject
);
680 // Tell PM_idle_timer_expiration() to ignore idle timer.
681 fIdleTimerPeriod
= 0;
684 PM_TRACE("[%s] %p %s done\n", getName(), this, __FUNCTION__
);
687 //*********************************************************************************
688 // [public virtual] addPowerChild
690 // Power Management is informing us who our children are.
691 //*********************************************************************************
693 IOReturn
IOService::addPowerChild ( IOService
* child
)
695 IOPowerConnection
* connection
= 0;
696 IOPMRequest
* requests
[3] = {0, 0, 0};
701 return kIOReturnBadArgument
;
703 if (!initialized
|| !child
->initialized
)
704 return IOPMNotYetInitialized
;
706 OUR_PMLog( kPMLogAddChild
, 0, 0 );
709 // Is this child already one of our children?
711 iter
= child
->getParentIterator( gIOPowerPlane
);
714 IORegistryEntry
* entry
;
717 while ((next
= iter
->getNextObject()))
719 if ((entry
= OSDynamicCast(IORegistryEntry
, next
)) &&
720 isChild(entry
, gIOPowerPlane
))
730 PM_DEBUG("[%s] %s (%p) is already a child\n",
731 getName(), child
->getName(), child
);
735 // Add the child to the power plane immediately, but the
736 // joining connection is marked as not ready.
737 // We want the child to appear in the power plane before
738 // returning to the caller, but don't want the caller to
739 // block on the PM work loop.
741 connection
= new IOPowerConnection
;
745 // Create a chain of PM requests to perform the bottom-half
746 // work from the PM work loop.
748 requests
[0] = acquirePMRequest(
750 /* type */ kIOPMRequestTypeAddPowerChild1
);
752 requests
[1] = acquirePMRequest(
754 /* type */ kIOPMRequestTypeAddPowerChild2
);
756 requests
[2] = acquirePMRequest(
758 /* type */ kIOPMRequestTypeAddPowerChild3
);
760 if (!requests
[0] || !requests
[1] || !requests
[2])
763 requests
[0]->setParentRequest( requests
[1] );
764 requests
[1]->setParentRequest( requests
[2] );
767 connection
->start(this);
768 connection
->setAwaitingAck(false);
769 connection
->setReadyFlag(false);
771 attachToChild( connection
, gIOPowerPlane
);
772 connection
->attachToChild( child
, gIOPowerPlane
);
774 // connection needs to be released
775 requests
[0]->fArg0
= connection
;
776 requests
[1]->fArg0
= connection
;
777 requests
[2]->fArg0
= connection
;
779 submitPMRequest( requests
, 3 );
780 return kIOReturnSuccess
;
784 if (connection
) connection
->release();
785 if (requests
[0]) releasePMRequest(requests
[0]);
786 if (requests
[1]) releasePMRequest(requests
[1]);
787 if (requests
[2]) releasePMRequest(requests
[2]);
789 // silent failure, to prevent platform drivers from adding the child
790 // to the root domain.
794 //*********************************************************************************
795 // [private] addPowerChild1
797 // Called on the power parent.
798 //*********************************************************************************
800 void IOService::addPowerChild1 ( IOPMRequest
* request
)
802 unsigned long tempDesire
= 0;
804 // Make us temporary usable before adding the child.
807 OUR_PMLog( kPMLogMakeUsable
, kPMLogMakeUsable
, fDeviceDesire
);
809 if (fControllingDriver
&& inPlane(gIOPowerPlane
) && fParentsKnowState
)
811 tempDesire
= fNumberOfPowerStates
- 1;
814 if (tempDesire
&& (fWeAreRoot
|| (fMaxCapability
>= tempDesire
)))
816 computeDesiredState( tempDesire
);
821 //*********************************************************************************
822 // [private] addPowerChild2
824 // Called on the joining child. Blocked behind addPowerChild1.
825 //*********************************************************************************
827 void IOService::addPowerChild2 ( IOPMRequest
* request
)
829 IOPowerConnection
* connection
= (IOPowerConnection
*) request
->fArg0
;
831 IOPMPowerFlags powerFlags
;
833 unsigned long powerState
;
834 unsigned long tempDesire
;
837 parent
= (IOService
*) connection
->getParentEntry(gIOPowerPlane
);
839 if (!parent
|| !inPlane(gIOPowerPlane
))
841 PM_DEBUG("[%s] addPowerChild2 not in power plane\n", getName());
845 // Parent will be waiting for us to complete this stage, safe to
846 // directly access parent's vars.
848 knowsState
= (parent
->fPowerStates
) && (parent
->fParentsKnowState
);
849 powerState
= parent
->fCurrentPowerState
;
852 powerFlags
= parent
->fPowerStates
[powerState
].outputPowerCharacter
;
856 // Set our power parent.
858 OUR_PMLog(kPMLogSetParent
, knowsState
, powerFlags
);
860 setParentInfo( powerFlags
, connection
, knowsState
);
862 connection
->setReadyFlag(true);
864 if ( fControllingDriver
&& fParentsKnowState
)
866 fMaxCapability
= fControllingDriver
->maxCapabilityForDomainState(fParentsCurrentPowerFlags
);
867 // initially change into the state we are already in
868 tempDesire
= fControllingDriver
->initialPowerStateForDomainState(fParentsCurrentPowerFlags
);
869 computeDesiredState(tempDesire
);
870 fPreviousRequest
= 0xffffffff;
875 //*********************************************************************************
876 // [private] addPowerChild3
878 // Called on the parent. Blocked behind addPowerChild2.
879 //*********************************************************************************
881 void IOService::addPowerChild3 ( IOPMRequest
* request
)
883 IOPowerConnection
* connection
= (IOPowerConnection
*) request
->fArg0
;
888 child
= (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
890 if (child
&& inPlane(gIOPowerPlane
))
892 if (child
->getProperty("IOPMStrictTreeOrder"))
894 PM_DEBUG("[%s] strict ordering enforced\n", getName());
895 fStrictTreeOrder
= true;
898 for (i
= 0; i
<= kMaxType
; i
++)
900 if ( fAggressivenessValid
[i
] )
902 child
->setAggressiveness(i
, fAggressivenessValue
[i
]);
908 PM_DEBUG("[%s] addPowerChild3 not in power plane\n", getName());
911 connection
->release();
914 //*********************************************************************************
915 // [public virtual deprecated] setPowerParent
917 // Power Management is informing us who our parent is.
918 // If we have a controlling driver, find out, given our newly-informed
919 // power domain state, what state it would be in, and then tell it
920 // to assume that state.
921 //*********************************************************************************
923 IOReturn
IOService::setPowerParent (
924 IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags powerFlags
)
926 return kIOReturnUnsupported
;
929 //*********************************************************************************
930 // [public virtual] removePowerChild
932 // Called on a parent whose child is being removed by PMstop().
933 //*********************************************************************************
935 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theNub
)
937 IORegistryEntry
* theChild
;
940 OUR_PMLog( kPMLogRemoveChild
, 0, 0 );
944 // detach nub from child
945 theChild
= theNub
->copyChildEntry(gIOPowerPlane
);
948 theNub
->detachFromChild(theChild
, gIOPowerPlane
);
951 // detach from the nub
952 detachFromChild(theNub
, gIOPowerPlane
);
954 // Are we awaiting an ack from this child?
955 if ( theNub
->getAwaitingAck() )
957 // yes, pretend we got one
958 theNub
->setAwaitingAck(false);
959 if (fHeadNotePendingAcks
!= 0 )
961 // that's one fewer ack to worry about
962 fHeadNotePendingAcks
--;
965 if ( fHeadNotePendingAcks
== 0 )
974 // Schedule a request to re-scan child desires and clamp bits.
975 if (!fWillAdjustPowerState
)
977 IOPMRequest
* request
;
979 request
= acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState
);
982 submitPMRequest( request
);
983 fWillAdjustPowerState
= true;
990 //*********************************************************************************
991 // [public virtual] registerPowerDriver
993 // A driver has called us volunteering to control power to our device.
994 //*********************************************************************************
996 IOReturn
IOService::registerPowerDriver (
997 IOService
* powerDriver
,
998 IOPMPowerState
* powerStates
,
999 unsigned long numberOfStates
)
1001 IOPMRequest
* request
;
1002 IOPMPowerState
* powerStatesCopy
= 0;
1005 return IOPMNotYetInitialized
;
1007 // Validate arguments.
1008 if (!powerStates
|| (numberOfStates
< 2))
1010 OUR_PMLog(kPMLogControllingDriverErr5
, numberOfStates
, 0);
1011 return kIOReturnBadArgument
;
1016 OUR_PMLog(kPMLogControllingDriverErr4
, 0, 0);
1017 return kIOReturnBadArgument
;
1020 if (powerStates
[0].version
!= kIOPMPowerStateVersion1
)
1022 OUR_PMLog(kPMLogControllingDriverErr1
, powerStates
[0].version
, 0);
1023 return kIOReturnBadArgument
;
1027 // Make a copy of the supplied power state array.
1028 powerStatesCopy
= IONew(IOPMPowerState
, numberOfStates
);
1029 if (!powerStatesCopy
)
1032 bcopy( powerStates
, powerStatesCopy
,
1033 sizeof(IOPMPowerState
) * numberOfStates
);
1035 request
= acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver
);
1039 powerDriver
->retain();
1040 request
->fArg0
= (void *) powerDriver
;
1041 request
->fArg1
= (void *) powerStatesCopy
;
1042 request
->fArg2
= (void *) numberOfStates
;
1044 submitPMRequest( request
);
1045 return kIOReturnSuccess
;
1049 if (powerStatesCopy
)
1050 IODelete(powerStatesCopy
, IOPMPowerState
, numberOfStates
);
1051 return kIOReturnNoMemory
;
1054 //*********************************************************************************
1055 // [private] handleRegisterPowerDriver
1056 //*********************************************************************************
1058 void IOService::handleRegisterPowerDriver ( IOPMRequest
* request
)
1060 IOService
* powerDriver
= (IOService
*) request
->fArg0
;
1061 IOPMPowerState
* powerStates
= (IOPMPowerState
*) request
->fArg1
;
1062 unsigned long numberOfStates
= (unsigned long) request
->fArg2
;
1066 PM_ASSERT_IN_GATE();
1067 assert(powerStates
);
1068 assert(powerDriver
);
1069 assert(numberOfStates
> 1);
1071 if ( !fNumberOfPowerStates
)
1073 OUR_PMLog(kPMLogControllingDriver
,
1074 (unsigned long) numberOfStates
,
1075 (unsigned long) powerStates
[0].version
);
1077 fPowerStates
= powerStates
;
1078 fNumberOfPowerStates
= numberOfStates
;
1079 fControllingDriver
= powerDriver
;
1080 fCurrentCapabilityFlags
= fPowerStates
[0].capabilityFlags
;
1082 // make a mask of all the character bits we know about
1083 fOutputPowerCharacterFlags
= 0;
1084 for ( i
= 0; i
< numberOfStates
; i
++ ) {
1085 fOutputPowerCharacterFlags
|= fPowerStates
[i
].outputPowerCharacter
;
1088 // Register powerDriver as interested, unless already done.
1089 // We don't want to register the default implementation since
1090 // it does nothing. One ramification of not always registering
1091 // is the one fewer retain count held.
1093 root
= getPlatform()->getProvider();
1096 ((OSMemberFunctionCast(void (*)(void),
1097 root
, &IOService::powerStateDidChangeTo
)) !=
1098 ((OSMemberFunctionCast(void (*)(void),
1099 this, &IOService::powerStateDidChangeTo
)))) ||
1100 ((OSMemberFunctionCast(void (*)(void),
1101 root
, &IOService::powerStateWillChangeTo
)) !=
1102 ((OSMemberFunctionCast(void (*)(void),
1103 this, &IOService::powerStateWillChangeTo
)))))
1105 if (fInterestedDrivers
->findItem(powerDriver
) == NULL
)
1108 fInterestedDrivers
->appendNewInformee(powerDriver
);
1113 if ( fNeedToBecomeUsable
) {
1114 fNeedToBecomeUsable
= false;
1115 fDeviceDesire
= fNumberOfPowerStates
- 1;
1118 if ( inPlane(gIOPowerPlane
) && fParentsKnowState
)
1120 unsigned long tempDesire
;
1121 fMaxCapability
= fControllingDriver
->maxCapabilityForDomainState(fParentsCurrentPowerFlags
);
1122 // initially change into the state we are already in
1123 tempDesire
= fControllingDriver
->initialPowerStateForDomainState(fParentsCurrentPowerFlags
);
1124 computeDesiredState(tempDesire
);
1130 OUR_PMLog(kPMLogControllingDriverErr2
, numberOfStates
, 0);
1131 IODelete(powerStates
, IOPMPowerState
, numberOfStates
);
1134 powerDriver
->release();
1137 //*********************************************************************************
1138 // [public virtual] registerInterestedDriver
1140 // Add the caller to our list of interested drivers and return our current
1141 // power state. If we don't have a power-controlling driver yet, we will
1142 // call this interested driver again later when we do get a driver and find
1143 // out what the current power state of the device is.
1144 //*********************************************************************************
1146 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* driver
)
1148 IOPMRequest
* request
;
1151 if (!initialized
|| !fInterestedDrivers
)
1152 return IOPMNotPowerManaged
;
1155 signal
= (!fInsertInterestSet
&& !fRemoveInterestSet
);
1156 if (fInsertInterestSet
== NULL
)
1157 fInsertInterestSet
= OSSet::withCapacity(4);
1158 if (fInsertInterestSet
)
1159 fInsertInterestSet
->setObject(driver
);
1164 request
= acquirePMRequest( this, kIOPMRequestTypeInterestChanged
);
1166 submitPMRequest( request
);
1169 // This return value cannot be trusted, but return a value
1170 // for those clients that care.
1172 OUR_PMLog(kPMLogInterestedDriver
, kIOPMDeviceUsable
, 2);
1173 return kIOPMDeviceUsable
;
1176 //*********************************************************************************
1177 // [public virtual] deRegisterInterestedDriver
1178 //*********************************************************************************
1180 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* driver
)
1182 IOPMinformeeList
* list
;
1183 IOPMinformee
* item
;
1184 IOPMRequest
* request
;
1187 if (!initialized
|| !fInterestedDrivers
)
1188 return IOPMNotPowerManaged
;
1191 signal
= (!fRemoveInterestSet
&& !fInsertInterestSet
);
1192 if (fRemoveInterestSet
== NULL
)
1193 fRemoveInterestSet
= OSSet::withCapacity(4);
1194 if (fRemoveInterestSet
)
1196 fRemoveInterestSet
->setObject(driver
);
1198 list
= fInterestedDrivers
;
1199 item
= list
->findItem(driver
);
1200 if (item
&& item
->active
)
1202 item
->active
= false;
1204 if (fDriverCallBusy
)
1205 PM_DEBUG("%s::deRegisterInterestedDriver() driver call busy\n", getName());
1211 request
= acquirePMRequest( this, kIOPMRequestTypeInterestChanged
);
1213 submitPMRequest( request
);
1219 //*********************************************************************************
1220 // [private] handleInterestChanged
1222 // Handle interest added or removed.
1223 //*********************************************************************************
1225 void IOService::handleInterestChanged( IOPMRequest
* request
)
1228 IOPMinformee
* informee
;
1229 IOPMinformeeList
* list
= fInterestedDrivers
;
1233 if (fInsertInterestSet
)
1235 while ((driver
= (IOService
*) fInsertInterestSet
->getAnyObject()))
1237 if ((list
->findItem(driver
) == NULL
) &&
1238 (!fRemoveInterestSet
||
1239 !fRemoveInterestSet
->containsObject(driver
)))
1241 informee
= list
->appendNewInformee(driver
);
1243 fInsertInterestSet
->removeObject(driver
);
1245 fInsertInterestSet
->release();
1246 fInsertInterestSet
= 0;
1249 if (fRemoveInterestSet
)
1251 while ((driver
= (IOService
*) fRemoveInterestSet
->getAnyObject()))
1253 informee
= list
->findItem(driver
);
1256 if (fHeadNotePendingAcks
&& informee
->timer
)
1258 informee
->timer
= 0;
1259 fHeadNotePendingAcks
--;
1261 list
->removeFromList(driver
);
1263 fRemoveInterestSet
->removeObject(driver
);
1265 fRemoveInterestSet
->release();
1266 fRemoveInterestSet
= 0;
1272 //*********************************************************************************
1273 // [public virtual] acknowledgePowerChange
1275 // After we notified one of the interested drivers or a power-domain child
1276 // of an impending change in power, it has called to say it is now
1277 // prepared for the change. If this object is the last to
1278 // acknowledge this change, we take whatever action we have been waiting
1280 // That may include acknowledging to our parent. In this case, we do it
1281 // last of all to insure that this doesn't cause the parent to call us some-
1282 // where else and alter data we are relying on here (like the very existance
1283 // of a "current change note".)
1284 //*********************************************************************************
1286 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
1288 IOPMRequest
* request
;
1291 return IOPMNotYetInitialized
;
1293 return kIOReturnBadArgument
;
1295 request
= acquirePMRequest( this, kIOPMRequestTypeAckPowerChange
);
1298 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__
);
1299 return kIOReturnNoMemory
;
1302 whichObject
->retain();
1303 request
->fArg0
= whichObject
;
1305 submitPMRequest( request
);
1309 //*********************************************************************************
1310 // [private] handleAcknowledgePowerChange
1311 //*********************************************************************************
1313 bool IOService::handleAcknowledgePowerChange ( IOPMRequest
* request
)
1315 IOPMinformee
* informee
;
1316 unsigned long childPower
= kIOPMUnknown
;
1317 IOService
* theChild
;
1318 IOService
* whichObject
;
1319 bool all_acked
= false;
1321 PM_ASSERT_IN_GATE();
1322 whichObject
= (IOService
*) request
->fArg0
;
1323 assert(whichObject
);
1325 // one of our interested drivers?
1326 informee
= fInterestedDrivers
->findItem( whichObject
);
1327 if ( informee
== NULL
)
1329 if ( !isChild(whichObject
, gIOPowerPlane
) )
1331 OUR_PMLog(kPMLogAcknowledgeErr1
, 0, 0);
1334 OUR_PMLog(kPMLogChildAcknowledge
, fHeadNotePendingAcks
, 0);
1337 OUR_PMLog(kPMLogDriverAcknowledge
, fHeadNotePendingAcks
, 0);
1340 if ( fHeadNotePendingAcks
!= 0 )
1342 assert(fPowerStates
!= NULL
);
1344 // yes, make sure we're expecting acks
1345 if ( informee
!= NULL
)
1347 // it's an interested driver
1348 // make sure we're expecting this ack
1349 if ( informee
->timer
!= 0 )
1351 #if LOG_SETPOWER_TIMES
1352 if (informee
->timer
> 0)
1354 uint64_t nsec
= computeTimeDeltaNS(&informee
->startTime
);
1355 if (nsec
> LOG_SETPOWER_TIMES
)
1356 PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
1357 informee
->whatObject
->getName(),
1358 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
1359 informee
->whatObject
,
1360 fName
, fCurrentPowerState
, fHeadNoteState
, NS_TO_MS(nsec
));
1364 informee
->timer
= 0;
1365 // that's one fewer to worry about
1366 fHeadNotePendingAcks
--;
1368 // this driver has already acked
1369 OUR_PMLog(kPMLogAcknowledgeErr2
, 0, 0);
1373 // make sure we're expecting this ack
1374 if ( ((IOPowerConnection
*)whichObject
)->getAwaitingAck() )
1376 // that's one fewer to worry about
1377 fHeadNotePendingAcks
--;
1378 ((IOPowerConnection
*)whichObject
)->setAwaitingAck(false);
1379 theChild
= (IOService
*)whichObject
->copyChildEntry(gIOPowerPlane
);
1382 childPower
= theChild
->currentPowerConsumption();
1383 theChild
->release();
1385 if ( childPower
== kIOPMUnknown
)
1387 fPowerStates
[fHeadNoteState
].staticPower
= kIOPMUnknown
;
1389 if ( fPowerStates
[fHeadNoteState
].staticPower
!= kIOPMUnknown
)
1391 fPowerStates
[fHeadNoteState
].staticPower
+= childPower
;
1397 if ( fHeadNotePendingAcks
== 0 ) {
1398 // yes, stop the timer
1400 // and now we can continue
1404 OUR_PMLog(kPMLogAcknowledgeErr3
, 0, 0); // not expecting anybody to ack
1409 whichObject
->release();
1414 //*********************************************************************************
1415 // [public virtual] acknowledgeSetPowerState
1417 // After we instructed our controlling driver to change power states,
1418 // it has called to say it has finished doing so.
1419 // We continue to process the power state change.
1420 //*********************************************************************************
1422 IOReturn
IOService::acknowledgeSetPowerState ( void )
1424 IOPMRequest
* request
;
1427 return IOPMNotYetInitialized
;
1429 request
= acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState
);
1432 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__
);
1433 return kIOReturnNoMemory
;
1436 submitPMRequest( request
);
1437 return kIOReturnSuccess
;
1440 //*********************************************************************************
1441 // [private] adjustPowerState
1443 // Child has signaled a change - child changed it's desire, new child added,
1444 // existing child removed. Adjust our power state accordingly.
1445 //*********************************************************************************
1447 void IOService::adjustPowerState( void )
1449 PM_ASSERT_IN_GATE();
1450 if (inPlane(gIOPowerPlane
))
1452 rebuildChildClampBits();
1453 computeDesiredState();
1454 if ( fControllingDriver
&& fParentsKnowState
)
1459 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__
);
1462 fWillAdjustPowerState
= false;
1465 //*********************************************************************************
1466 // [public deprecated] powerDomainWillChangeTo
1468 // Called by the power-hierarchy parent notifying of a new power state
1469 // in the power domain.
1470 // We enqueue a parent power-change to our queue of power changes.
1471 // This may or may not cause us to change power, depending on what
1472 // kind of change is occuring in the domain.
1473 //*********************************************************************************
1475 IOReturn
IOService::powerDomainWillChangeTo (
1476 IOPMPowerFlags newPowerFlags
,
1477 IOPowerConnection
* whichParent
)
1480 return kIOReturnUnsupported
;
1483 //*********************************************************************************
1484 // [private] handlePowerDomainWillChangeTo
1485 //*********************************************************************************
1487 void IOService::handlePowerDomainWillChangeTo ( IOPMRequest
* request
)
1489 IOPMPowerFlags newPowerFlags
= (IOPMPowerFlags
) request
->fArg0
;
1490 IOPowerConnection
* whichParent
= (IOPowerConnection
*) request
->fArg1
;
1491 bool powerWillDrop
= (bool) request
->fArg2
;
1494 IOPowerConnection
* connection
;
1495 unsigned long newPowerState
;
1496 IOPMPowerFlags combinedPowerFlags
;
1497 bool savedParentsKnowState
;
1498 IOReturn result
= IOPMAckImplied
;
1500 PM_ASSERT_IN_GATE();
1501 OUR_PMLog(kPMLogWillChange
, newPowerFlags
, 0);
1503 if (!inPlane(gIOPowerPlane
))
1505 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__
);
1509 savedParentsKnowState
= fParentsKnowState
;
1511 // Combine parents' power flags to determine our maximum state
1512 // within the new power domain
1513 combinedPowerFlags
= 0;
1515 iter
= getParentIterator(gIOPowerPlane
);
1518 while ( (next
= iter
->getNextObject()) )
1520 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
1522 if ( connection
== whichParent
)
1523 combinedPowerFlags
|= newPowerFlags
;
1525 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
1531 if ( fControllingDriver
)
1533 newPowerState
= fControllingDriver
->maxCapabilityForDomainState(
1534 combinedPowerFlags
);
1536 result
= enqueuePowerChange(
1537 /* flags */ IOPMParentInitiated
| IOPMDomainWillChange
,
1538 /* power state */ newPowerState
,
1539 /* domain state */ combinedPowerFlags
,
1540 /* connection */ whichParent
,
1541 /* parent state */ newPowerFlags
);
1544 // If parent is dropping power, immediately update the parent's
1545 // capability flags. Any future merging of parent(s) combined
1546 // power flags should account for this power drop.
1550 setParentInfo(newPowerFlags
, whichParent
, true);
1553 // Parent is expecting an ACK from us. If we did not embark on a state
1554 // transition, when enqueuePowerChang() returns IOPMAckImplied. We are
1555 // still required to issue an ACK to our parent.
1557 if (IOPMAckImplied
== result
)
1560 parent
= (IOService
*) whichParent
->copyParentEntry(gIOPowerPlane
);
1564 parent
->acknowledgePowerChange( whichParent
);
1569 // If the parent registers it's power driver late, then this is the
1570 // first opportunity to tell our parent about our desire.
1572 if (!savedParentsKnowState
&& fParentsKnowState
)
1574 PM_TRACE("[%s] powerDomainWillChangeTo: parentsKnowState = true\n",
1576 ask_parent( fDesiredPowerState
);
1580 //*********************************************************************************
1581 // [public deprecated] powerDomainDidChangeTo
1583 // Called by the power-hierarchy parent after the power state of the power domain
1584 // has settled at a new level.
1585 // We enqueue a parent power-change to our queue of power changes.
1586 // This may or may not cause us to change power, depending on what
1587 // kind of change is occuring in the domain.
1588 //*********************************************************************************
1590 IOReturn
IOService::powerDomainDidChangeTo (
1591 IOPMPowerFlags newPowerFlags
,
1592 IOPowerConnection
* whichParent
)
1595 return kIOReturnUnsupported
;
1598 //*********************************************************************************
1599 // [private] handlePowerDomainDidChangeTo
1600 //*********************************************************************************
1602 void IOService::handlePowerDomainDidChangeTo ( IOPMRequest
* request
)
1604 IOPMPowerFlags newPowerFlags
= (IOPMPowerFlags
) request
->fArg0
;
1605 IOPowerConnection
* whichParent
= (IOPowerConnection
*) request
->fArg1
;
1606 unsigned long newPowerState
;
1607 bool savedParentsKnowState
;
1608 IOReturn result
= IOPMAckImplied
;
1610 PM_ASSERT_IN_GATE();
1611 OUR_PMLog(kPMLogDidChange
, newPowerFlags
, 0);
1613 if (!inPlane(gIOPowerPlane
))
1615 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__
);
1619 savedParentsKnowState
= fParentsKnowState
;
1621 setParentInfo(newPowerFlags
, whichParent
, true);
1623 if ( fControllingDriver
)
1625 newPowerState
= fControllingDriver
->maxCapabilityForDomainState(
1626 fParentsCurrentPowerFlags
);
1628 result
= enqueuePowerChange(
1629 /* flags */ IOPMParentInitiated
| IOPMDomainDidChange
,
1630 /* power state */ newPowerState
,
1631 /* domain state */ fParentsCurrentPowerFlags
,
1632 /* connection */ whichParent
,
1633 /* parent state */ 0);
1636 // Parent is expecting an ACK from us. If we did not embark on a state
1637 // transition, when enqueuePowerChang() returns IOPMAckImplied. We are
1638 // still required to issue an ACK to our parent.
1640 if (IOPMAckImplied
== result
)
1643 parent
= (IOService
*) whichParent
->copyParentEntry(gIOPowerPlane
);
1647 parent
->acknowledgePowerChange( whichParent
);
1652 // If the parent registers it's power driver late, then this is the
1653 // first opportunity to tell our parent about our desire.
1655 if (!savedParentsKnowState
&& fParentsKnowState
)
1657 PM_TRACE("[%s] powerDomainDidChangeTo: parentsKnowState = true\n",
1659 ask_parent( fDesiredPowerState
);
1663 //*********************************************************************************
1664 // [private] setParentInfo
1666 // Set our connection data for one specific parent, and then combine all the parent
1668 //*********************************************************************************
1670 void IOService::setParentInfo (
1671 IOPMPowerFlags newPowerFlags
,
1672 IOPowerConnection
* whichParent
,
1677 IOPowerConnection
* conn
;
1679 PM_ASSERT_IN_GATE();
1681 // set our connection data
1682 whichParent
->setParentCurrentPowerFlags(newPowerFlags
);
1683 whichParent
->setParentKnowsState(knowsState
);
1685 // recompute our parent info
1686 fParentsCurrentPowerFlags
= 0;
1687 fParentsKnowState
= true;
1689 iter
= getParentIterator(gIOPowerPlane
);
1692 while ( (next
= iter
->getNextObject()) )
1694 if ( (conn
= OSDynamicCast(IOPowerConnection
, next
)) )
1696 fParentsKnowState
&= conn
->parentKnowsState();
1697 fParentsCurrentPowerFlags
|= conn
->parentCurrentPowerFlags();
1704 //*********************************************************************************
1705 // [private] rebuildChildClampBits
1707 // The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1708 // indicate that one of our children (or grandchildren or great-grandchildren ...)
1709 // doesn't support idle or system sleep in its current state. Since we don't track
1710 // the origin of each bit, every time any child changes state we have to clear
1711 // these bits and rebuild them.
1712 //*********************************************************************************
1714 void IOService::rebuildChildClampBits ( void )
1719 IOPowerConnection
* connection
;
1720 unsigned long powerState
;
1722 // A child's desires has changed. We need to rebuild the child-clamp bits in
1723 // our power state array. Start by clearing the bits in each power state.
1725 for ( i
= 0; i
< fNumberOfPowerStates
; i
++ )
1727 fPowerStates
[i
].capabilityFlags
&= ~(kIOPMChildClamp
| kIOPMChildClamp2
);
1730 // Loop through the children. When we encounter the calling child, save the
1731 // computed state as this child's desire. And set the ChildClamp bits in any
1732 // of our states that some child has clamp on.
1734 iter
= getChildIterator(gIOPowerPlane
);
1737 while ( (next
= iter
->getNextObject()) )
1739 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
1741 if (connection
->getReadyFlag() == false)
1743 PM_CONNECT("[%s] %s: connection not ready\n",
1744 getName(), __FUNCTION__
);
1748 powerState
= connection
->getDesiredDomainState();
1749 if (powerState
< fNumberOfPowerStates
)
1751 if ( connection
->getPreventIdleSleepFlag() )
1752 fPowerStates
[powerState
].capabilityFlags
|= kIOPMChildClamp
;
1753 if ( connection
->getPreventSystemSleepFlag() )
1754 fPowerStates
[powerState
].capabilityFlags
|= kIOPMChildClamp2
;
1762 //*********************************************************************************
1763 // [public virtual] requestPowerDomainState
1765 // The child of a power domain calls it parent here to request power of a certain
1767 //*********************************************************************************
1769 IOReturn
IOService::requestPowerDomainState (
1770 IOPMPowerFlags desiredState
,
1771 IOPowerConnection
* whichChild
,
1772 unsigned long specification
)
1775 unsigned long computedState
;
1776 unsigned long theDesiredState
;
1780 return IOPMNotYetInitialized
;
1782 if (gIOPMWorkLoop
->onThread() == false)
1784 PM_DEBUG("[%s] called requestPowerDomainState\n", getName());
1785 return kIOReturnSuccess
;
1788 theDesiredState
= desiredState
& ~(kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
1790 OUR_PMLog(kPMLogRequestDomain
, desiredState
, specification
);
1792 if (!isChild(whichChild
, gIOPowerPlane
))
1793 return kIOReturnNotAttached
;
1795 if (fControllingDriver
== NULL
|| !fPowerStates
)
1796 return IOPMNotYetInitialized
;
1798 child
= (IOService
*) whichChild
->getChildEntry(gIOPowerPlane
);
1801 switch (specification
) {
1802 case IOPMLowestState
:
1804 while ( i
< fNumberOfPowerStates
)
1806 if ( ( fPowerStates
[i
].outputPowerCharacter
& theDesiredState
) ==
1807 (theDesiredState
& fOutputPowerCharacterFlags
) )
1813 if ( i
>= fNumberOfPowerStates
)
1815 return IOPMNoSuchState
;
1819 case IOPMNextLowerState
:
1820 i
= fCurrentPowerState
- 1;
1821 while ( (int) i
>= 0 )
1823 if ( ( fPowerStates
[i
].outputPowerCharacter
& theDesiredState
) ==
1824 (theDesiredState
& fOutputPowerCharacterFlags
) )
1832 return IOPMNoSuchState
;
1836 case IOPMHighestState
:
1837 i
= fNumberOfPowerStates
;
1838 while ( (int) i
>= 0 )
1841 if ( ( fPowerStates
[i
].outputPowerCharacter
& theDesiredState
) ==
1842 (theDesiredState
& fOutputPowerCharacterFlags
) )
1849 return IOPMNoSuchState
;
1853 case IOPMNextHigherState
:
1854 i
= fCurrentPowerState
+ 1;
1855 while ( i
< fNumberOfPowerStates
)
1857 if ( ( fPowerStates
[i
].outputPowerCharacter
& theDesiredState
) ==
1858 (theDesiredState
& fOutputPowerCharacterFlags
) )
1864 if ( i
== fNumberOfPowerStates
)
1866 return IOPMNoSuchState
;
1871 return IOPMBadSpecification
;
1876 // Clamp removed on the initial power request from a new child.
1878 if (fClampOn
&& !whichChild
->childHasRequestedPower())
1880 PM_TRACE("[%s] %p power clamp removed (child = %p)\n",
1881 getName(), this, whichChild
);
1886 // Record the child's desires on the connection.
1888 whichChild
->setDesiredDomainState( computedState
);
1889 whichChild
->setPreventIdleSleepFlag( desiredState
& kIOPMPreventIdleSleep
);
1890 whichChild
->setPreventSystemSleepFlag( desiredState
& kIOPMPreventSystemSleep
);
1891 whichChild
->setChildHasRequestedPower();
1893 if (whichChild
->getReadyFlag() == false)
1896 // Issue a ping for us to re-evaluate all children desires and
1897 // possibly change power state.
1899 if (!fWillAdjustPowerState
&& !fDeviceOverrides
)
1901 IOPMRequest
* childRequest
;
1903 childRequest
= acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState
);
1906 submitPMRequest( childRequest
);
1907 fWillAdjustPowerState
= true;
1914 //*********************************************************************************
1915 // [public virtual] temporaryPowerClampOn
1917 // A power domain wants to clamp its power on till it has children which
1918 // will thendetermine the power domain state.
1920 // We enter the highest state until addPowerChild is called.
1921 //*********************************************************************************
1923 IOReturn
IOService::temporaryPowerClampOn ( void )
1925 IOPMRequest
* request
;
1928 return IOPMNotYetInitialized
;
1930 request
= acquirePMRequest( this, kIOPMRequestTypeTemporaryPowerClamp
);
1932 return kIOReturnNoMemory
;
1934 submitPMRequest( request
);
1938 //*********************************************************************************
1939 // [public virtual] makeUsable
1941 // Some client of our device is asking that we become usable. Although
1942 // this has not come from a subclassed device object, treat it exactly
1943 // as if it had. In this way, subsequent requests for lower power from
1944 // a subclassed device object will pre-empt this request.
1946 // We treat this as a subclass object request to switch to the
1947 // highest power state.
1948 //*********************************************************************************
1950 IOReturn
IOService::makeUsable ( void )
1952 IOPMRequest
* request
;
1955 return IOPMNotYetInitialized
;
1957 OUR_PMLog(kPMLogMakeUsable
, 0, 0);
1959 request
= acquirePMRequest( this, kIOPMRequestTypeMakeUsable
);
1961 return kIOReturnNoMemory
;
1963 submitPMRequest( request
);
1967 //*********************************************************************************
1968 // [private] handleMakeUsable
1970 // Handle a request to become usable.
1971 //*********************************************************************************
1973 void IOService::handleMakeUsable ( IOPMRequest
* request
)
1975 PM_ASSERT_IN_GATE();
1976 if ( fControllingDriver
)
1978 fDeviceDesire
= fNumberOfPowerStates
- 1;
1979 computeDesiredState();
1980 if ( inPlane(gIOPowerPlane
) && fParentsKnowState
)
1987 fNeedToBecomeUsable
= true;
1991 //*********************************************************************************
1992 // [public virtual] currentCapability
1993 //*********************************************************************************
1995 IOPMPowerFlags
IOService::currentCapability ( void )
1998 return IOPMNotPowerManaged
;
2000 return fCurrentCapabilityFlags
;
2003 //*********************************************************************************
2004 // [public virtual] changePowerStateTo
2006 // For some reason, our power-controlling driver has decided it needs to change
2007 // power state. We enqueue the power change so that appropriate parties
2008 // will be notified, and then we will instruct the driver to make the change.
2009 //*********************************************************************************
2011 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
2013 IOPMRequest
* request
;
2016 return IOPMNotYetInitialized
;
2018 OUR_PMLog(kPMLogChangeStateTo
, ordinal
, 0);
2020 request
= acquirePMRequest( this, kIOPMRequestTypeChangePowerStateTo
);
2022 return kIOReturnNoMemory
;
2024 request
->fArg0
= (void *) ordinal
;
2025 request
->fArg1
= (void *) false;
2027 // Avoid needless downwards power transitions by clamping power in
2028 // computeDesiredState() until the delayed request is processed.
2030 if (gIOPMWorkLoop
->inGate())
2032 fTempClampPowerState
= max(fTempClampPowerState
, ordinal
);
2034 request
->fArg1
= (void *) true;
2037 submitPMRequest( request
);
2041 //*********************************************************************************
2042 // [private] handleChangePowerStateTo
2043 //*********************************************************************************
2045 void IOService::handleChangePowerStateTo ( IOPMRequest
* request
)
2047 unsigned long ordinal
= (unsigned long) request
->fArg0
;
2049 PM_ASSERT_IN_GATE();
2052 assert(fTempClampCount
!= 0);
2053 if (fTempClampCount
)
2055 if (!fTempClampCount
)
2056 fTempClampPowerState
= 0;
2059 if ( fControllingDriver
&& (ordinal
< fNumberOfPowerStates
))
2061 fDriverDesire
= ordinal
;
2062 computeDesiredState();
2063 if ( inPlane(gIOPowerPlane
) && fParentsKnowState
)
2070 //*********************************************************************************
2071 // [public virtual] changePowerStateToPriv
2073 // For some reason, a subclassed device object has decided it needs to change
2074 // power state. We enqueue the power change so that appropriate parties
2075 // will be notified, and then we will instruct the driver to make the change.
2076 //*********************************************************************************
2078 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
2080 IOPMRequest
* request
;
2083 return IOPMNotYetInitialized
;
2085 request
= acquirePMRequest( this, kIOPMRequestTypeChangePowerStateToPriv
);
2087 return kIOReturnNoMemory
;
2089 request
->fArg0
= (void *) ordinal
;
2090 request
->fArg1
= (void *) false;
2092 // Avoid needless downwards power transitions by clamping power in
2093 // computeDesiredState() until the delayed request is processed.
2095 if (gIOPMWorkLoop
->inGate())
2097 fTempClampPowerState
= max(fTempClampPowerState
, ordinal
);
2099 request
->fArg1
= (void *) true;
2102 submitPMRequest( request
);
2106 //*********************************************************************************
2107 // [private] handleChangePowerStateToPriv
2108 //*********************************************************************************
2110 void IOService::handleChangePowerStateToPriv ( IOPMRequest
* request
)
2112 unsigned long ordinal
= (unsigned long) request
->fArg0
;
2114 PM_ASSERT_IN_GATE();
2115 OUR_PMLog(kPMLogChangeStateToPriv
, ordinal
, 0);
2118 assert(fTempClampCount
!= 0);
2119 if (fTempClampCount
)
2121 if (!fTempClampCount
)
2122 fTempClampPowerState
= 0;
2125 if ( fControllingDriver
&& (ordinal
< fNumberOfPowerStates
))
2127 fDeviceDesire
= ordinal
;
2128 computeDesiredState();
2129 if ( inPlane(gIOPowerPlane
) && fParentsKnowState
)
2136 //*********************************************************************************
2137 // [private] computeDesiredState
2138 //*********************************************************************************
2140 void IOService::computeDesiredState ( unsigned long tempDesire
)
2144 IOPowerConnection
* connection
;
2145 unsigned long newDesiredState
= 0;
2146 unsigned long childDesire
= 0;
2147 unsigned long deviceDesire
;
2150 deviceDesire
= tempDesire
;
2152 deviceDesire
= fDeviceDesire
;
2154 // If clamp is on, always override deviceDesire to max.
2156 if (fClampOn
&& fNumberOfPowerStates
)
2157 deviceDesire
= fNumberOfPowerStates
- 1;
2159 // Compute the maximum of our children's desires,
2160 // our controlling driver's desire, and the subclass device's desire.
2162 if ( !fDeviceOverrides
)
2164 iter
= getChildIterator(gIOPowerPlane
);
2167 while ( (next
= iter
->getNextObject()) )
2169 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
2171 if (connection
->getReadyFlag() == false)
2173 PM_CONNECT("[%s] %s: connection not ready\n",
2174 getName(), __FUNCTION__
);
2178 if (connection
->getDesiredDomainState() > childDesire
)
2179 childDesire
= connection
->getDesiredDomainState();
2185 fChildrenDesire
= childDesire
;
2186 newDesiredState
= max(childDesire
, fDriverDesire
);
2189 newDesiredState
= max(deviceDesire
, newDesiredState
);
2190 if (fTempClampCount
&& (fTempClampPowerState
< fNumberOfPowerStates
))
2191 newDesiredState
= max(fTempClampPowerState
, newDesiredState
);
2193 fDesiredPowerState
= newDesiredState
;
2195 // Limit check against number of power states.
2197 if (fNumberOfPowerStates
== 0)
2198 fDesiredPowerState
= 0;
2199 else if (fDesiredPowerState
>= fNumberOfPowerStates
)
2200 fDesiredPowerState
= fNumberOfPowerStates
- 1;
2202 // Restart idle timer if stopped and deviceDesire has increased.
2204 if (fDeviceDesire
&& fActivityTimerStopped
)
2206 fActivityTimerStopped
= false;
2207 start_PM_idle_timer();
2210 // Invalidate cached tickle power state when desires change, and not
2211 // due to a tickle request. This invalidation must occur before the
2212 // power state change to minimize races. We want to err on the side
2213 // of servicing more activity tickles rather than dropping one when
2214 // the device is in a low power state.
2216 if (fPMRequest
&& (fPMRequest
->getType() != kIOPMRequestTypeActivityTickle
) &&
2217 (fActivityTicklePowerState
!= -1))
2219 IOLockLock(fActivityLock
);
2220 fActivityTicklePowerState
= -1;
2221 IOLockUnlock(fActivityLock
);
2224 PM_TRACE(" NewState %ld, Child %ld, Driver %ld, Device %ld, Clamp %d (%ld)\n",
2225 fDesiredPowerState
, childDesire
, fDriverDesire
, deviceDesire
,
2226 fClampOn
, fTempClampCount
? fTempClampPowerState
: 0);
2229 //*********************************************************************************
2230 // [private] changeState
2232 // A subclass object, our controlling driver, or a power domain child
2233 // has asked for a different power state. Here we compute what new
2234 // state we should enter and enqueue the change (or start it).
2235 //*********************************************************************************
2237 IOReturn
IOService::changeState ( void )
2241 PM_ASSERT_IN_GATE();
2242 assert(inPlane(gIOPowerPlane
));
2243 assert(fParentsKnowState
);
2244 assert(fControllingDriver
);
2246 result
= enqueuePowerChange(
2247 /* flags */ IOPMWeInitiated
,
2248 /* power state */ fDesiredPowerState
,
2249 /* domain state */ 0,
2251 /* parent state */ 0);
2256 //*********************************************************************************
2257 // [public virtual] currentPowerConsumption
2259 //*********************************************************************************
2261 unsigned long IOService::currentPowerConsumption ( void )
2264 return kIOPMUnknown
;
2266 return fCurrentPowerConsumption
;
2269 //*********************************************************************************
2270 // [public virtual] getPMworkloop
2271 //*********************************************************************************
2273 IOWorkLoop
* IOService::getPMworkloop ( void )
2275 return gIOPMWorkLoop
;
2278 //*********************************************************************************
2279 // [public virtual] activityTickle
2281 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
2282 // flag to be set, and the device state checked. If the device has been
2283 // powered down, it is powered up again.
2284 // The tickle with parameter kIOPMSubclassPolicy is ignored here and
2285 // should be intercepted by a subclass.
2286 //*********************************************************************************
2288 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
)
2290 IOPMRequest
* request
;
2291 bool noPowerChange
= true;
2293 if ( initialized
&& stateNumber
&& (type
== kIOPMSuperclassPolicy1
) )
2295 IOLockLock(fActivityLock
);
2297 // Record device activity for the idle timer handler.
2299 fDeviceActive
= true;
2300 clock_get_uptime(&fDeviceActiveTimestamp
);
2302 // Record the last tickle power state.
2303 // This helps to filter out redundant tickles as
2304 // this function may be called from the data path.
2306 if (fActivityTicklePowerState
< (long)stateNumber
)
2308 fActivityTicklePowerState
= stateNumber
;
2309 noPowerChange
= false;
2311 request
= acquirePMRequest( this, kIOPMRequestTypeActivityTickle
);
2314 request
->fArg0
= (void *) stateNumber
; // power state
2315 request
->fArg1
= (void *) true; // power rise
2316 submitPMRequest(request
);
2320 IOLockUnlock(fActivityLock
);
2323 // Returns false if the activityTickle might cause a transition to a
2324 // higher powered state, true otherwise.
2326 return noPowerChange
;
2329 //*********************************************************************************
2330 // [public virtual] setIdleTimerPeriod
2332 // A subclass policy-maker is going to use our standard idleness
2333 // detection service. Make a command queue and an idle timer and
2334 // connect them to the power management workloop. Finally,
2336 //*********************************************************************************
2338 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
2340 IOWorkLoop
* wl
= getPMworkloop();
2342 if (!initialized
|| !wl
)
2343 return IOPMNotYetInitialized
;
2345 OUR_PMLog(PMsetIdleTimerPeriod
, period
, 0);
2347 fIdleTimerPeriod
= period
;
2351 // make the timer event
2352 if ( fIdleTimerEventSource
== NULL
)
2354 IOTimerEventSource
* timerSrc
;
2356 timerSrc
= IOTimerEventSource::timerEventSource(
2357 this, PM_idle_timer_expired
);
2359 if (timerSrc
&& (wl
->addEventSource(timerSrc
) != kIOReturnSuccess
))
2361 timerSrc
->release();
2365 fIdleTimerEventSource
= timerSrc
;
2368 start_PM_idle_timer();
2373 //******************************************************************************
2374 // [public virtual] nextIdleTimeout
2376 // Returns how many "seconds from now" the device should idle into its
2377 // next lowest power state.
2378 //******************************************************************************
2380 SInt32
IOService::nextIdleTimeout(
2381 AbsoluteTime currentTime
,
2382 AbsoluteTime lastActivity
,
2383 unsigned int powerState
)
2390 // Calculate time difference using funky macro from clock.h.
2391 delta
= currentTime
;
2392 SUB_ABSOLUTETIME(&delta
, &lastActivity
);
2394 // Figure it in seconds.
2395 absolutetime_to_nanoseconds(delta
, &delta_ns
);
2396 delta_secs
= (SInt32
)(delta_ns
/ NSEC_PER_SEC
);
2398 // Be paranoid about delta somehow exceeding timer period.
2399 if (delta_secs
< (int) fIdleTimerPeriod
)
2400 delay_secs
= (int) fIdleTimerPeriod
- delta_secs
;
2402 delay_secs
= (int) fIdleTimerPeriod
;
2404 return (SInt32
)delay_secs
;
2407 //******************************************************************************
2408 // [public virtual] start_PM_idle_timer
2410 // The parameter is a pointer to us. Use it to call our timeout method.
2411 //******************************************************************************
2413 void IOService::start_PM_idle_timer ( void )
2415 static const int maxTimeout
= 100000;
2416 static const int minTimeout
= 1;
2417 AbsoluteTime uptime
;
2420 if (!initialized
|| !fIdleTimerEventSource
)
2423 IOLockLock(fActivityLock
);
2425 clock_get_uptime(&uptime
);
2427 // Subclasses may modify idle sleep algorithm
2428 idle_in
= nextIdleTimeout(uptime
, fDeviceActiveTimestamp
, fCurrentPowerState
);
2430 // Check for out-of range responses
2431 if (idle_in
> maxTimeout
)
2433 // use standard implementation
2434 idle_in
= IOService::nextIdleTimeout(uptime
,
2435 fDeviceActiveTimestamp
,
2436 fCurrentPowerState
);
2437 } else if (idle_in
< minTimeout
) {
2438 idle_in
= fIdleTimerPeriod
;
2441 IOLockUnlock(fActivityLock
);
2443 fIdleTimerEventSource
->setTimeout(idle_in
, NSEC_PER_SEC
);
2446 //*********************************************************************************
2447 // [private] PM_idle_timer_expired
2449 // The parameter is a pointer to us. Use it to call our timeout method.
2450 //*********************************************************************************
2452 void PM_idle_timer_expired ( OSObject
* ourSelves
, IOTimerEventSource
* )
2454 ((IOService
*)ourSelves
)->PM_idle_timer_expiration();
2457 //*********************************************************************************
2458 // [public virtual] PM_idle_timer_expiration
2460 // The idle timer has expired. If there has been activity since the last
2461 // expiration, just restart the timer and return. If there has not been
2462 // activity, switch to the next lower power state and restart the timer.
2463 //*********************************************************************************
2465 void IOService::PM_idle_timer_expiration ( void )
2467 IOPMRequest
* request
;
2468 bool restartTimer
= true;
2470 if ( !initialized
|| !fIdleTimerPeriod
)
2473 IOLockLock(fActivityLock
);
2475 // Check for device activity (tickles) over last timer period.
2479 // Device was active - do not drop power, restart timer.
2480 fDeviceActive
= false;
2484 // No device activity - drop power state by one level.
2485 // Decrement the cached tickle power state when possible.
2486 // This value may be (-1) before activityTickle() is called,
2487 // but the power drop request must be issued regardless.
2489 if (fActivityTicklePowerState
> 0)
2491 fActivityTicklePowerState
--;
2494 request
= acquirePMRequest( this, kIOPMRequestTypeActivityTickle
);
2497 request
->fArg0
= (void *) 0; // power state (irrelevant)
2498 request
->fArg1
= (void *) false; // power drop
2499 submitPMRequest( request
);
2501 // Do not restart timer until after the tickle request has been
2504 restartTimer
= false;
2508 IOLockUnlock(fActivityLock
);
2511 start_PM_idle_timer();
2514 //*********************************************************************************
2515 // [public virtual] command_received
2517 //*********************************************************************************
2519 void IOService::command_received ( void *statePtr
, void *, void * , void * )
2523 //*********************************************************************************
2524 // [public virtual] setAggressiveness
2526 // Pass on the input parameters to all power domain children. All those which are
2527 // power domains will pass it on to their children, etc.
2528 //*********************************************************************************
2530 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
2534 IOPowerConnection
* connection
;
2538 return IOPMNotYetInitialized
;
2540 if (getPMRootDomain() == this)
2541 OUR_PMLog(kPMLogSetAggressiveness
, type
, newLevel
);
2543 if ( type
<= kMaxType
)
2545 fAggressivenessValue
[type
] = newLevel
;
2546 fAggressivenessValid
[type
] = true;
2549 iter
= getChildIterator(gIOPowerPlane
);
2552 while ( (next
= iter
->getNextObject()) )
2554 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
2556 if (connection
->getReadyFlag() == false)
2558 PM_CONNECT("[%s] %s: connection not ready\n",
2559 getName(), __FUNCTION__
);
2563 child
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
2566 child
->setAggressiveness(type
, newLevel
);
2577 //*********************************************************************************
2578 // [public virtual] getAggressiveness
2580 // Called by the user client.
2581 //*********************************************************************************
2583 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
2585 if ( !initialized
|| (type
> kMaxType
) )
2586 return kIOReturnBadArgument
;
2588 if ( !fAggressivenessValid
[type
] )
2589 return kIOReturnInvalid
;
2591 *currentLevel
= fAggressivenessValue
[type
];
2593 return kIOReturnSuccess
;
2596 //*********************************************************************************
2597 // [public] getPowerState
2599 //*********************************************************************************
2601 UInt32
IOService::getPowerState ( void )
2606 return fCurrentPowerState
;
2609 //*********************************************************************************
2610 // [public virtual] systemWake
2612 // Pass this to all power domain children. All those which are
2613 // power domains will pass it on to their children, etc.
2614 //*********************************************************************************
2616 IOReturn
IOService::systemWake ( void )
2620 IOPowerConnection
* connection
;
2621 IOService
* theChild
;
2623 OUR_PMLog(kPMLogSystemWake
, 0, 0);
2625 iter
= getChildIterator(gIOPowerPlane
);
2628 while ( (next
= iter
->getNextObject()) )
2630 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
2632 if (connection
->getReadyFlag() == false)
2634 PM_CONNECT("[%s] %s: connection not ready\n",
2635 getName(), __FUNCTION__
);
2639 theChild
= (IOService
*)connection
->copyChildEntry(gIOPowerPlane
);
2642 theChild
->systemWake();
2643 theChild
->release();
2650 if ( fControllingDriver
!= NULL
)
2652 if ( fControllingDriver
->didYouWakeSystem() )
2661 //*********************************************************************************
2662 // [public virtual] temperatureCriticalForZone
2663 //*********************************************************************************
2665 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
2667 IOService
* theParent
;
2670 OUR_PMLog(kPMLogCriticalTemp
, 0, 0);
2672 if ( inPlane(gIOPowerPlane
) && !fWeAreRoot
)
2674 theNub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
2677 theParent
= (IOService
*)theNub
->copyParentEntry(gIOPowerPlane
);
2681 theParent
->temperatureCriticalForZone(whichZone
);
2682 theParent
->release();
2689 //*********************************************************************************
2690 // [public] powerOverrideOnPriv
2691 //*********************************************************************************
2693 IOReturn
IOService::powerOverrideOnPriv ( void )
2695 IOPMRequest
* request
;
2698 return IOPMNotYetInitialized
;
2700 if (gIOPMWorkLoop
->inGate())
2702 fDeviceOverrides
= true;
2706 request
= acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv
);
2708 return kIOReturnNoMemory
;
2710 submitPMRequest( request
);
2714 //*********************************************************************************
2715 // [public] powerOverrideOffPriv
2716 //*********************************************************************************
2718 IOReturn
IOService::powerOverrideOffPriv ( void )
2720 IOPMRequest
* request
;
2723 return IOPMNotYetInitialized
;
2725 if (gIOPMWorkLoop
->inGate())
2727 fDeviceOverrides
= false;
2731 request
= acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv
);
2733 return kIOReturnNoMemory
;
2735 submitPMRequest( request
);
2739 //*********************************************************************************
2740 // [private] handlePowerOverrideChanged
2741 //*********************************************************************************
2743 void IOService::handlePowerOverrideChanged ( IOPMRequest
* request
)
2745 PM_ASSERT_IN_GATE();
2746 if (request
->getType() == kIOPMRequestTypePowerOverrideOnPriv
)
2748 OUR_PMLog(kPMLogOverrideOn
, 0, 0);
2749 fDeviceOverrides
= true;
2753 OUR_PMLog(kPMLogOverrideOff
, 0, 0);
2754 fDeviceOverrides
= false;
2757 if (fControllingDriver
&& inPlane(gIOPowerPlane
) && fParentsKnowState
)
2759 computeDesiredState();
2764 //*********************************************************************************
2765 // [private] enqueuePowerChange
2766 //*********************************************************************************
2768 IOReturn
IOService::enqueuePowerChange (
2769 unsigned long flags
,
2770 unsigned long whatStateOrdinal
,
2771 unsigned long domainState
,
2772 IOPowerConnection
* whichParent
,
2773 unsigned long singleParentState
)
2775 changeNoteItem changeNote
;
2776 IOPMPowerState
* powerStatePtr
;
2778 PM_ASSERT_IN_GATE();
2779 assert( fMachineState
== kIOPM_Finished
);
2780 assert( whatStateOrdinal
< fNumberOfPowerStates
);
2782 if (whatStateOrdinal
>= fNumberOfPowerStates
)
2783 return IOPMAckImplied
;
2785 powerStatePtr
= &fPowerStates
[whatStateOrdinal
];
2787 // Initialize the change note
2788 changeNote
.flags
= flags
;
2789 changeNote
.newStateNumber
= whatStateOrdinal
;
2790 changeNote
.outputPowerCharacter
= powerStatePtr
->outputPowerCharacter
;
2791 changeNote
.inputPowerRequirement
= powerStatePtr
->inputPowerRequirement
;
2792 changeNote
.capabilityFlags
= powerStatePtr
->capabilityFlags
;
2793 changeNote
.parent
= NULL
;
2795 if (flags
& IOPMParentInitiated
)
2797 changeNote
.domainState
= domainState
;
2798 changeNote
.parent
= whichParent
;
2799 changeNote
.singleParentState
= singleParentState
;
2802 if (flags
& IOPMWeInitiated
)
2804 start_our_change(&changeNote
);
2809 return start_parent_change(&changeNote
);
2813 //*********************************************************************************
2814 // [private] notifyInterestedDrivers
2815 //*********************************************************************************
2817 bool IOService::notifyInterestedDrivers ( void )
2819 IOPMinformee
* informee
;
2820 IOPMinformeeList
* list
= fInterestedDrivers
;
2821 DriverCallParam
* param
;
2824 PM_ASSERT_IN_GATE();
2825 assert( fDriverCallBusy
== false );
2826 assert( fDriverCallParamCount
== 0 );
2827 assert( fHeadNotePendingAcks
== 0 );
2829 count
= list
->numberOfItems();
2831 goto done
; // no interested drivers
2833 // Allocate an array of interested drivers and their return values
2834 // for the callout thread. Everything else is still "owned" by the
2835 // PM work loop, which can run to process acknowledgePowerChange()
2838 param
= (DriverCallParam
*) fDriverCallParamPtr
;
2839 if (count
> fDriverCallParamSlots
)
2841 if (fDriverCallParamSlots
)
2843 assert(fDriverCallParamPtr
);
2844 IODelete(fDriverCallParamPtr
, DriverCallParam
, fDriverCallParamSlots
);
2845 fDriverCallParamPtr
= 0;
2846 fDriverCallParamSlots
= 0;
2849 param
= IONew(DriverCallParam
, count
);
2851 goto done
; // no memory
2853 fDriverCallParamPtr
= (void *) param
;
2854 fDriverCallParamSlots
= count
;
2857 informee
= list
->firstInList();
2859 for (IOItemCount i
= 0; i
< count
; i
++)
2861 informee
->timer
= -1;
2862 param
[i
].Target
= informee
;
2864 informee
= list
->nextInList( informee
);
2867 fDriverCallParamCount
= count
;
2868 fHeadNotePendingAcks
= count
;
2870 // Machine state will be blocked pending callout thread completion.
2873 fDriverCallBusy
= true;
2875 thread_call_enter( fDriverCallEntry
);
2879 // no interested drivers or did not schedule callout thread due to error.
2883 //*********************************************************************************
2884 // [private] notifyInterestedDriversDone
2885 //*********************************************************************************
2887 void IOService::notifyInterestedDriversDone ( void )
2889 IOPMinformee
* informee
;
2891 DriverCallParam
* param
;
2894 PM_ASSERT_IN_GATE();
2895 param
= (DriverCallParam
*) fDriverCallParamPtr
;
2896 count
= fDriverCallParamCount
;
2898 assert( fDriverCallBusy
== false );
2899 assert( fMachineState
== kIOPM_DriverThreadCallDone
);
2903 for (IOItemCount i
= 0; i
< count
; i
++, param
++)
2905 informee
= (IOPMinformee
*) param
->Target
;
2906 result
= param
->Result
;
2908 if ((result
== IOPMAckImplied
) || (result
< 0))
2910 // child return IOPMAckImplied
2911 informee
->timer
= 0;
2912 fHeadNotePendingAcks
--;
2914 else if (informee
->timer
)
2916 assert(informee
->timer
== -1);
2918 // Driver has not acked, and has returned a positive result.
2919 // Enforce a minimum permissible timeout value.
2920 // Make the min value large enough so timeout is less likely
2921 // to occur if a driver misinterpreted that the return value
2922 // should be in microsecond units. And make it large enough
2923 // to be noticeable if a driver neglects to ack.
2925 if (result
< kMinAckTimeoutTicks
)
2926 result
= kMinAckTimeoutTicks
;
2928 informee
->timer
= (result
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
2930 // else, child has already acked or driver has removed interest,
2931 // and head_note_pendingAcks decremented.
2932 // informee may have been removed from the interested drivers list,
2933 // thus the informee must be retained across the callout.
2935 informee
->release();
2938 fDriverCallParamCount
= 0;
2940 if ( fHeadNotePendingAcks
)
2942 OUR_PMLog(kPMLogStartAckTimer
, 0, 0);
2947 // Hop back to original machine state path (from notifyAll)
2948 fMachineState
= fNextMachineState
;
2953 //*********************************************************************************
2954 // [private] notifyChildren
2955 //*********************************************************************************
2957 void IOService::notifyChildren ( void )
2961 IOPowerConnection
* connection
;
2962 OSArray
* children
= 0;
2964 if (fStrictTreeOrder
)
2965 children
= OSArray::withCapacity(8);
2967 // Sum child power consumption in notifyChild()
2968 fPowerStates
[fHeadNoteState
].staticPower
= 0;
2970 iter
= getChildIterator(gIOPowerPlane
);
2973 while ((next
= iter
->getNextObject()))
2975 if ((connection
= OSDynamicCast(IOPowerConnection
, next
)))
2977 if (connection
->getReadyFlag() == false)
2979 PM_CONNECT("[%s] %s: connection not ready\n",
2980 getName(), __FUNCTION__
);
2985 children
->setObject( connection
);
2987 notifyChild( connection
,
2988 fDriverCallReason
== kDriverCallInformPreChange
);
2996 if (children
->getCount() == 0)
2998 children
->release();
3003 assert(fNotifyChildArray
== 0);
3004 fNotifyChildArray
= children
;
3005 fNextMachineState
= fMachineState
;
3006 fMachineState
= kIOPM_NotifyChildrenDone
;
3011 //*********************************************************************************
3012 // [private] notifyChildrenDone
3013 //*********************************************************************************
3015 void IOService::notifyChildrenDone ( void )
3017 PM_ASSERT_IN_GATE();
3018 assert(fNotifyChildArray
);
3019 assert(fMachineState
== kIOPM_NotifyChildrenDone
);
3021 // Interested drivers have all acked (if any), ack timer stopped.
3022 // Notify one child, wait for it's ack, then repeat for next child.
3023 // This is a workaround for some drivers with multiple instances at
3024 // the same branch in the power tree, but the driver is slow to power
3025 // up unless the tree ordering is observed. Problem observed only on
3026 // system wake, not on system sleep.
3028 // We have the ability to power off in reverse child index order.
3029 // That works nicely on some machines, but not on all HW configs.
3031 if (fNotifyChildArray
->getCount())
3033 IOPowerConnection
* connection
;
3034 connection
= (IOPowerConnection
*) fNotifyChildArray
->getObject(0);
3035 fNotifyChildArray
->removeObject(0);
3036 notifyChild( connection
, fDriverCallReason
== kDriverCallInformPreChange
);
3040 fNotifyChildArray
->release();
3041 fNotifyChildArray
= 0;
3042 fMachineState
= fNextMachineState
;
3046 //*********************************************************************************
3047 // [private] notifyAll
3048 //*********************************************************************************
3050 IOReturn
IOService::notifyAll ( bool is_prechange
)
3052 // Save the next machine_state to be restored by notifyInterestedDriversDone()
3054 PM_ASSERT_IN_GATE();
3055 fNextMachineState
= fMachineState
;
3056 fMachineState
= kIOPM_DriverThreadCallDone
;
3057 fDriverCallReason
= is_prechange
?
3058 kDriverCallInformPreChange
: kDriverCallInformPostChange
;
3060 if (!notifyInterestedDrivers())
3061 notifyInterestedDriversDone();
3063 return IOPMWillAckLater
;
3066 //*********************************************************************************
3067 // [private, static] pmDriverCallout
3069 // Thread call context
3070 //*********************************************************************************
3072 IOReturn
IOService::actionDriverCalloutDone (
3074 void * arg0
, void * arg1
,
3075 void * arg2
, void * arg3
)
3077 IOServicePM
* pwrMgt
= (IOServicePM
*) arg0
;
3080 fDriverCallBusy
= false;
3083 if (gIOPMReplyQueue
)
3084 gIOPMReplyQueue
->signalWorkAvailable();
3086 return kIOReturnSuccess
;
3089 void IOService::pmDriverCallout ( IOService
* from
)
3092 switch (from
->fDriverCallReason
)
3094 case kDriverCallSetPowerState
:
3095 from
->driverSetPowerState();
3098 case kDriverCallInformPreChange
:
3099 case kDriverCallInformPostChange
:
3100 from
->driverInformPowerChange();
3104 IOPanic("IOService::pmDriverCallout bad machine state");
3107 gIOPMWorkLoop
->runAction(actionDriverCalloutDone
,
3109 /* arg0 */ (void *) from
->pwrMgt
);
3112 //*********************************************************************************
3113 // [private] driverSetPowerState
3115 // Thread call context
3116 //*********************************************************************************
3118 void IOService::driverSetPowerState ( void )
3121 unsigned long powerState
;
3122 DriverCallParam
* param
;
3126 assert( fDriverCallBusy
);
3127 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3129 assert( fDriverCallParamCount
== 1 );
3131 driver
= fControllingDriver
;
3132 powerState
= fHeadNoteState
;
3136 OUR_PMLog( kPMLogProgramHardware
, (UInt32
) this, powerState
);
3137 clock_get_uptime(&fDriverCallStartTime
);
3138 result
= driver
->setPowerState( powerState
, this );
3139 clock_get_uptime(&end
);
3140 OUR_PMLog((UInt32
) -kPMLogProgramHardware
, (UInt32
) this, (UInt32
) result
);
3142 #if LOG_SETPOWER_TIMES
3143 if ((result
== IOPMAckImplied
) || (result
< 0))
3147 SUB_ABSOLUTETIME(&end
, &fDriverCallStartTime
);
3148 absolutetime_to_nanoseconds(end
, &nsec
);
3149 if (nsec
> LOG_SETPOWER_TIMES
)
3150 PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
3151 fName
, this, fCurrentPowerState
, powerState
, NS_TO_MS(nsec
));
3156 result
= kIOPMAckImplied
;
3158 param
->Result
= result
;
3161 //*********************************************************************************
3162 // [private] driverInformPowerChange
3164 // Thread call context
3165 //*********************************************************************************
3167 void IOService::driverInformPowerChange ( void )
3170 IOPMinformee
* informee
;
3173 IOPMPowerFlags powerFlags
;
3174 unsigned long powerState
;
3175 DriverCallParam
* param
;
3178 assert( fDriverCallBusy
);
3179 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3180 count
= fDriverCallParamCount
;
3181 assert( count
&& param
);
3183 powerFlags
= fHeadNoteCapabilityFlags
;
3184 powerState
= fHeadNoteState
;
3186 for (IOItemCount i
= 0; i
< count
; i
++)
3188 informee
= (IOPMinformee
*) param
->Target
;
3189 driver
= informee
->whatObject
;
3191 if (!fWillPMStop
&& informee
->active
)
3193 if (fDriverCallReason
== kDriverCallInformPreChange
)
3195 OUR_PMLog(kPMLogInformDriverPreChange
, (UInt32
) this, powerState
);
3196 clock_get_uptime(&informee
->startTime
);
3197 result
= driver
->powerStateWillChangeTo(powerFlags
, powerState
, this);
3198 clock_get_uptime(&end
);
3199 OUR_PMLog((UInt32
)-kPMLogInformDriverPreChange
, (UInt32
) this, result
);
3203 OUR_PMLog(kPMLogInformDriverPostChange
, (UInt32
) this, powerState
);
3204 clock_get_uptime(&informee
->startTime
);
3205 result
= driver
->powerStateDidChangeTo(powerFlags
, powerState
, this);
3206 clock_get_uptime(&end
);
3207 OUR_PMLog((UInt32
)-kPMLogInformDriverPostChange
, (UInt32
) this, result
);
3210 #if LOG_SETPOWER_TIMES
3211 if ((result
== IOPMAckImplied
) || (result
< 0))
3215 SUB_ABSOLUTETIME(&end
, &informee
->startTime
);
3216 absolutetime_to_nanoseconds(end
, &nsec
);
3217 if (nsec
> LOG_SETPOWER_TIMES
)
3218 PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
3220 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
3221 driver
, fName
, fCurrentPowerState
, powerState
, NS_TO_MS(nsec
));
3226 result
= kIOPMAckImplied
;
3228 param
->Result
= result
;
3233 //*********************************************************************************
3234 // [private] notifyChild
3236 // Notify a power domain child of an upcoming power change.
3237 // If the object acknowledges the current change, we return TRUE.
3238 //*********************************************************************************
3240 bool IOService::notifyChild ( IOPowerConnection
* theNub
, bool is_prechange
)
3242 IOReturn k
= IOPMAckImplied
;
3243 unsigned long childPower
;
3244 IOService
* theChild
;
3245 IOPMRequest
* childRequest
;
3248 PM_ASSERT_IN_GATE();
3249 theChild
= (IOService
*)(theNub
->copyChildEntry(gIOPowerPlane
));
3256 // Unless the child handles the notification immediately and returns
3257 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
3258 fHeadNotePendingAcks
++;
3259 theNub
->setAwaitingAck(true);
3261 requestType
= is_prechange
?
3262 kIOPMRequestTypePowerDomainWillChange
:
3263 kIOPMRequestTypePowerDomainDidChange
;
3265 childRequest
= acquirePMRequest( theChild
, requestType
);
3268 childRequest
->fArg0
= (void *) fHeadNoteOutputFlags
;
3269 childRequest
->fArg1
= (void *) theNub
;
3270 childRequest
->fArg2
= (void *) (fHeadNoteState
< fCurrentPowerState
);
3271 theChild
->submitPMRequest( childRequest
);
3272 k
= IOPMWillAckLater
;
3277 fHeadNotePendingAcks
--;
3278 theNub
->setAwaitingAck(false);
3279 childPower
= theChild
->currentPowerConsumption();
3280 if ( childPower
== kIOPMUnknown
)
3282 fPowerStates
[fHeadNoteState
].staticPower
= kIOPMUnknown
;
3284 if ( fPowerStates
[fHeadNoteState
].staticPower
!= kIOPMUnknown
)
3286 fPowerStates
[fHeadNoteState
].staticPower
+= childPower
;
3291 theChild
->release();
3292 return (k
== IOPMAckImplied
);
3295 //*********************************************************************************
3296 // [private] OurChangeTellClientsPowerDown
3298 // All registered applications and kernel clients have positively acknowledged our
3299 // intention of lowering power. Here we notify them all that we will definitely
3300 // lower the power. If we don't have to wait for any of them to acknowledge, we
3301 // carry on by notifying interested drivers. Otherwise, we do wait.
3302 //*********************************************************************************
3304 void IOService::OurChangeTellClientsPowerDown ( void )
3306 fMachineState
= kIOPM_OurChangeTellPriorityClientsPowerDown
;
3307 tellChangeDown1(fHeadNoteState
);
3310 //*********************************************************************************
3311 // [private] OurChangeTellPriorityClientsPowerDown
3313 // All registered applications and kernel clients have positively acknowledged our
3314 // intention of lowering power. Here we notify "priority" clients that we are
3315 // lowering power. If we don't have to wait for any of them to acknowledge, we
3316 // carry on by notifying interested drivers. Otherwise, we do wait.
3317 //*********************************************************************************
3319 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
3321 fMachineState
= kIOPM_OurChangeNotifyInterestedDriversWillChange
;
3322 tellChangeDown2(fHeadNoteState
);
3325 //*********************************************************************************
3326 // [private] OurChangeNotifyInterestedDriversWillChange
3328 // All registered applications and kernel clients have acknowledged our notification
3329 // that we are lowering power. Here we notify interested drivers. If we don't have
3330 // to wait for any of them to acknowledge, we instruct our power driver to make the
3331 // change. Otherwise, we do wait.
3332 //*********************************************************************************
3334 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
3336 fMachineState
= kIOPM_OurChangeSetPowerState
;
3340 //*********************************************************************************
3341 // [private] OurChangeSetPowerState
3343 // All interested drivers have acknowledged our pre-change notification of a power
3344 // change we initiated. Here we instruct our controlling driver to make
3345 // the change to the hardware. If it does so, we continue processing
3346 // (waiting for settle and notifying interested parties post-change.)
3347 // If it doesn't, we have to wait for it to acknowledge and then continue.
3348 //*********************************************************************************
3350 void IOService::OurChangeSetPowerState ( void )
3352 fNextMachineState
= kIOPM_OurChangeWaitForPowerSettle
;
3353 fMachineState
= kIOPM_DriverThreadCallDone
;
3354 fDriverCallReason
= kDriverCallSetPowerState
;
3356 if (notifyControllingDriver() == false)
3357 notifyControllingDriverDone();
3360 //*********************************************************************************
3361 // [private] OurChangeWaitForPowerSettle
3363 // Our controlling driver has changed power state on the hardware
3364 // during a power change we initiated. Here we see if we need to wait
3365 // for power to settle before continuing. If not, we continue processing
3366 // (notifying interested parties post-change). If so, we wait and
3368 //*********************************************************************************
3370 void IOService::OurChangeWaitForPowerSettle ( void )
3372 fMachineState
= kIOPM_OurChangeNotifyInterestedDriversDidChange
;
3373 fSettleTimeUS
= compute_settle_time();
3374 if ( fSettleTimeUS
)
3376 startSettleTimer(fSettleTimeUS
);
3380 //*********************************************************************************
3381 // [private] OurChangeNotifyInterestedDriversDidChange
3383 // Power has settled on a power change we initiated. Here we notify
3384 // all our interested parties post-change. If they all acknowledge, we're
3385 // done with this change note, and we can start on the next one.
3386 // Otherwise we have to wait for acknowledgements and finish up later.
3387 //*********************************************************************************
3389 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
3391 fMachineState
= kIOPM_OurChangeFinish
;
3395 //*********************************************************************************
3396 // [private] OurChangeFinish
3398 // Power has settled on a power change we initiated, and
3399 // all our interested parties have acknowledged. We're
3400 // done with this change note, and we can start on the next one.
3401 //*********************************************************************************
3403 void IOService::OurChangeFinish ( void )
3408 //*********************************************************************************
3409 // [private] ParentDownTellPriorityClientsPowerDown
3411 // All applications and kernel clients have been notified of a power lowering
3412 // initiated by the parent and we had to wait for responses. Here
3413 // we notify any priority clients. If they all ack, we continue with the power change.
3414 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
3415 //*********************************************************************************
3417 void IOService::ParentDownTellPriorityClientsPowerDown ( void )
3419 fMachineState
= kIOPM_ParentDownNotifyInterestedDriversWillChange
;
3420 tellChangeDown2(fHeadNoteState
);
3423 //*********************************************************************************
3424 // [private] ParentDownNotifyInterestedDriversWillChange
3426 // All applications and kernel clients have been notified of a power lowering
3427 // initiated by the parent and we had to wait for their responses. Here we notify
3428 // any interested drivers and power domain children. If they all ack, we continue
3429 // with the power change.
3430 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
3431 //*********************************************************************************
3433 void IOService::ParentDownNotifyInterestedDriversWillChange ( void )
3435 fMachineState
= kIOPM_ParentDownSetPowerState
;
3439 //*********************************************************************************
3440 // [private] ParentDownSetPowerState
3442 // We had to wait for it, but all parties have acknowledged our pre-change
3443 // notification of a power lowering initiated by the parent.
3444 // Here we instruct our controlling driver
3445 // to put the hardware in the state it needs to be in when the domain is
3446 // lowered. If it does so, we continue processing
3447 // (waiting for settle and acknowledging the parent.)
3448 // If it doesn't, we have to wait for it to acknowledge and then continue.
3449 //*********************************************************************************
3451 void IOService::ParentDownSetPowerState ( void )
3453 fNextMachineState
= kIOPM_ParentDownWaitForPowerSettle
;
3454 fMachineState
= kIOPM_DriverThreadCallDone
;
3455 fDriverCallReason
= kDriverCallSetPowerState
;
3457 if (notifyControllingDriver() == false)
3458 notifyControllingDriverDone();
3461 //*********************************************************************************
3462 // [private] ParentDownWaitForPowerSettle
3464 // Our controlling driver has changed power state on the hardware
3465 // during a power change initiated by our parent. We have had to wait
3466 // for acknowledgement from interested parties, or we have had to wait
3467 // for the controlling driver to change the state. Here we see if we need
3468 // to wait for power to settle before continuing. If not, we continue
3469 // processing (acknowledging our preparedness to the parent).
3470 // If so, we wait and continue later.
3471 //*********************************************************************************
3473 void IOService::ParentDownWaitForPowerSettle ( void )
3475 fMachineState
= kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange
;
3476 fSettleTimeUS
= compute_settle_time();
3477 if ( fSettleTimeUS
)
3479 startSettleTimer(fSettleTimeUS
);
3483 //*********************************************************************************
3484 // [private] ParentDownNotifyDidChangeAndAcknowledgeChange
3486 // Power has settled on a power change initiated by our parent. Here we
3487 // notify interested parties.
3488 //*********************************************************************************
3490 void IOService::ParentDownNotifyDidChangeAndAcknowledgeChange ( void )
3492 fMachineState
= kIOPM_ParentDownAcknowledgeChange
;
3496 //*********************************************************************************
3497 // [private] ParentDownAcknowledgeChange
3499 // We had to wait for it, but all parties have acknowledged our post-change
3500 // notification of a power lowering initiated by the parent.
3501 // Here we acknowledge the parent.
3502 // We are done with this change note, and we can start on the next one.
3503 //*********************************************************************************
3505 void IOService::ParentDownAcknowledgeChange ( void )
3507 IORegistryEntry
* nub
;
3510 nub
= fHeadNoteParent
;
3513 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
3516 parent
->acknowledgePowerChange((IOService
*)nub
);
3522 //*********************************************************************************
3523 // [private] ParentUpSetPowerState
3525 // Our parent has informed us via powerStateDidChange that it has
3526 // raised the power in our power domain, and we have had to wait
3527 // for some interested party to acknowledge our notification.
3528 // Here we instruct our controlling
3529 // driver to program the hardware to take advantage of the higher domain
3530 // power. If it does so, we continue processing
3531 // (waiting for settle and notifying interested parties post-change.)
3532 // If it doesn't, we have to wait for it to acknowledge and then continue.
3533 //*********************************************************************************
3535 void IOService::ParentUpSetPowerState ( void )
3537 fNextMachineState
= kIOPM_ParentUpWaitForSettleTime
;
3538 fMachineState
= kIOPM_DriverThreadCallDone
;
3539 fDriverCallReason
= kDriverCallSetPowerState
;
3541 if (notifyControllingDriver() == false)
3542 notifyControllingDriverDone();
3545 //*********************************************************************************
3546 // [private] ParentUpWaitForSettleTime
3548 // Our controlling driver has changed power state on the hardware
3549 // during a power raise initiated by the parent, but we had to wait for it.
3550 // Here we see if we need to wait for power to settle before continuing.
3551 // If not, we continue processing (notifying interested parties post-change).
3552 // If so, we wait and continue later.
3553 //*********************************************************************************
3555 void IOService::ParentUpWaitForSettleTime ( void )
3557 fMachineState
= kIOPM_ParentUpNotifyInterestedDriversDidChange
;
3558 fSettleTimeUS
= compute_settle_time();
3559 if ( fSettleTimeUS
)
3561 startSettleTimer(fSettleTimeUS
);
3565 //*********************************************************************************
3566 // [private] ParentUpNotifyInterestedDriversDidChange
3568 // Power has settled on a power raise initiated by the parent.
3569 // Here we notify all our interested parties post-change. If they all acknowledge,
3570 // we're done with this change note, and we can start on the next one.
3571 // Otherwise we have to wait for acknowledgements and finish up later.
3572 //*********************************************************************************
3574 void IOService::ParentUpNotifyInterestedDriversDidChange ( void )
3576 fMachineState
= kIOPM_ParentUpAcknowledgePowerChange
;
3580 //*********************************************************************************
3581 // [private] ParentUpAcknowledgePowerChange
3583 // All parties have acknowledged our post-change notification of a power
3584 // raising initiated by the parent. Here we acknowledge the parent.
3585 // We are done with this change note, and we can start on the next one.
3586 //*********************************************************************************
3588 void IOService::ParentUpAcknowledgePowerChange ( void )
3590 IORegistryEntry
* nub
;
3593 nub
= fHeadNoteParent
;
3596 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
3599 parent
->acknowledgePowerChange((IOService
*)nub
);
3605 //*********************************************************************************
3606 // [private] all_done
3608 // A power change is complete, and the used post-change note is at
3609 // the head of the queue. Remove it and set myCurrentState to the result
3610 // of the change. Start up the next change in queue.
3611 //*********************************************************************************
3613 void IOService::all_done ( void )
3615 unsigned long previous_state
;
3617 fMachineState
= kIOPM_Finished
;
3620 if ( fHeadNoteFlags
& IOPMWeInitiated
)
3622 // could our driver switch to the new state?
3623 if ( !( fHeadNoteFlags
& IOPMNotDone
) )
3625 // we changed, tell our parent
3628 ask_parent(fHeadNoteState
);
3631 // yes, did power raise?
3632 if ( fCurrentPowerState
< fHeadNoteState
)
3634 // yes, inform clients and apps
3635 tellChangeUp (fHeadNoteState
);
3637 previous_state
= fCurrentPowerState
;
3639 fCurrentPowerState
= fHeadNoteState
;
3641 fPMVars
->myCurrentState
= fCurrentPowerState
;
3643 OUR_PMLog(kPMLogChangeDone
, fCurrentPowerState
, 0);
3645 // inform subclass policy-maker
3646 if (!fWillPMStop
&& fParentsKnowState
)
3647 powerChangeDone(previous_state
);
3649 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
3653 // parent's power change
3654 if ( fHeadNoteFlags
& IOPMParentInitiated
)
3656 if (((fHeadNoteFlags
& IOPMDomainWillChange
) && (fCurrentPowerState
>= fHeadNoteState
)) ||
3657 ((fHeadNoteFlags
& IOPMDomainDidChange
) && (fCurrentPowerState
< fHeadNoteState
)))
3660 if ( fCurrentPowerState
< fHeadNoteState
)
3662 // yes, inform clients and apps
3663 tellChangeUp (fHeadNoteState
);
3666 previous_state
= fCurrentPowerState
;
3667 fCurrentPowerState
= fHeadNoteState
;
3669 fPMVars
->myCurrentState
= fCurrentPowerState
;
3671 fMaxCapability
= fControllingDriver
->maxCapabilityForDomainState(fHeadNoteDomainState
);
3673 OUR_PMLog(kPMLogChangeDone
, fCurrentPowerState
, 0);
3675 // inform subclass policy-maker
3676 if (!fWillPMStop
&& fParentsKnowState
)
3677 powerChangeDone(previous_state
);
3679 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
3683 if (fCurrentPowerState
< fNumberOfPowerStates
)
3685 const IOPMPowerState
* powerStatePtr
= &fPowerStates
[fCurrentPowerState
];
3687 fCurrentCapabilityFlags
= powerStatePtr
->capabilityFlags
;
3688 if (fCurrentCapabilityFlags
& kIOPMStaticPowerValid
)
3689 fCurrentPowerConsumption
= powerStatePtr
->staticPower
;
3693 //*********************************************************************************
3694 // [public] settleTimerExpired
3696 // Power has settled after our last change. Notify interested parties that
3697 // there is a new power state.
3698 //*********************************************************************************
3700 void IOService::settleTimerExpired ( void )
3705 //*********************************************************************************
3706 // [private] compute_settle_time
3708 // Compute the power-settling delay in microseconds for the
3709 // change from myCurrentState to head_note_state.
3710 //*********************************************************************************
3712 unsigned long IOService::compute_settle_time ( void )
3714 unsigned long totalTime
;
3717 PM_ASSERT_IN_GATE();
3719 // compute total time to attain the new state
3721 i
= fCurrentPowerState
;
3723 // we're lowering power
3724 if ( fHeadNoteState
< fCurrentPowerState
)
3726 while ( i
> fHeadNoteState
)
3728 totalTime
+= fPowerStates
[i
].settleDownTime
;
3733 // we're raising power
3734 if ( fHeadNoteState
> fCurrentPowerState
)
3736 while ( i
< fHeadNoteState
)
3738 totalTime
+= fPowerStates
[i
+1].settleUpTime
;
3746 //*********************************************************************************
3747 // [private] startSettleTimer
3749 // Enter a power-settling delay in microseconds and start a timer for that delay.
3750 //*********************************************************************************
3752 IOReturn
IOService::startSettleTimer ( unsigned long delay
)
3754 AbsoluteTime deadline
;
3758 clock_interval_to_deadline(delay
, kMicrosecondScale
, &deadline
);
3759 pending
= thread_call_enter_delayed(fSettleTimer
, deadline
);
3760 if (pending
) release();
3765 //*********************************************************************************
3766 // [public] ackTimerTick
3768 // The acknowledgement timeout periodic timer has ticked.
3769 // If we are awaiting acks for a power change notification,
3770 // we decrement the timer word of each interested driver which hasn't acked.
3771 // If a timer word becomes zero, we pretend the driver aknowledged.
3772 // If we are waiting for the controlling driver to change the power
3773 // state of the hardware, we decrement its timer word, and if it becomes
3774 // zero, we pretend the driver acknowledged.
3776 // Returns true if the timer tick made it possible to advance to the next
3777 // machine state, false otherwise.
3778 //*********************************************************************************
3780 void IOService::ack_timer_ticked ( void )
3785 bool IOService::ackTimerTick( void )
3787 IOPMinformee
* nextObject
;
3790 PM_ASSERT_IN_GATE();
3791 switch (fMachineState
) {
3792 case kIOPM_OurChangeWaitForPowerSettle
:
3793 case kIOPM_ParentDownWaitForPowerSettle
:
3794 case kIOPM_ParentUpWaitForSettleTime
:
3795 // are we waiting for controlling driver to acknowledge?
3796 if ( fDriverTimer
> 0 )
3798 // yes, decrement timer tick
3800 if ( fDriverTimer
== 0 )
3802 // controlling driver is tardy
3803 uint64_t nsec
= computeTimeDeltaNS(&fDriverCallStartTime
);
3804 OUR_PMLog(kPMLogCtrlDriverTardy
, 0, 0);
3805 setProperty(kIOPMTardyAckSPSKey
, kOSBooleanTrue
);
3806 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
3807 fName
, this, fCurrentPowerState
, fHeadNoteState
, NS_TO_MS(nsec
));
3809 if (gIOKitDebug
& kIOLogDebugPower
)
3811 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
3812 fName
, this, fCurrentPowerState
, fHeadNoteState
, NS_TO_MS(nsec
));
3816 // Unblock state machine and pretend driver has acked.
3820 // still waiting, set timer again
3826 case kIOPM_OurChangeSetPowerState
:
3827 case kIOPM_OurChangeFinish
:
3828 case kIOPM_ParentDownSetPowerState
:
3829 case kIOPM_ParentDownAcknowledgeChange
:
3830 case kIOPM_ParentUpSetPowerState
:
3831 case kIOPM_ParentUpAcknowledgePowerChange
:
3832 case kIOPM_NotifyChildrenDone
:
3833 // are we waiting for interested parties to acknowledge?
3834 if ( fHeadNotePendingAcks
!= 0 )
3836 // yes, go through the list of interested drivers
3837 nextObject
= fInterestedDrivers
->firstInList();
3838 // and check each one
3839 while ( nextObject
!= NULL
)
3841 if ( nextObject
->timer
> 0 )
3843 nextObject
->timer
--;
3844 // this one should have acked by now
3845 if ( nextObject
->timer
== 0 )
3847 uint64_t nsec
= computeTimeDeltaNS(&nextObject
->startTime
);
3848 OUR_PMLog(kPMLogIntDriverTardy
, 0, 0);
3849 nextObject
->whatObject
->setProperty(kIOPMTardyAckPSCKey
, kOSBooleanTrue
);
3850 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
3851 nextObject
->whatObject
->getName(),
3852 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
3853 nextObject
->whatObject
, fName
, fCurrentPowerState
, fHeadNoteState
,
3856 // Pretend driver has acked.
3857 fHeadNotePendingAcks
--;
3860 nextObject
= fInterestedDrivers
->nextInList(nextObject
);
3863 // is that the last?
3864 if ( fHeadNotePendingAcks
== 0 )
3866 // yes, we can continue
3869 // no, set timer again
3875 case kIOPM_ParentDownTellPriorityClientsPowerDown
:
3876 case kIOPM_ParentDownNotifyInterestedDriversWillChange
:
3877 case kIOPM_OurChangeTellClientsPowerDown
:
3878 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
3879 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
3880 // apps didn't respond in time
3881 cleanClientResponses(true);
3882 OUR_PMLog(kPMLogClientTardy
, 0, 1);
3883 if (fMachineState
== kIOPM_OurChangeTellClientsPowerDown
)
3885 // tardy equates to veto
3886 fDoNotPowerDown
= true;
3892 PM_TRACE("[%s] unexpected ack timer tick (state = %ld)\n",
3893 getName(), fMachineState
);
3899 //*********************************************************************************
3900 // [private] start_ack_timer
3901 //*********************************************************************************
3903 void IOService::start_ack_timer ( void )
3905 start_ack_timer( ACK_TIMER_PERIOD
, kNanosecondScale
);
3908 void IOService::start_ack_timer ( UInt32 interval
, UInt32 scale
)
3910 AbsoluteTime deadline
;
3913 clock_interval_to_deadline(interval
, scale
, &deadline
);
3916 pending
= thread_call_enter_delayed(fAckTimer
, deadline
);
3917 if (pending
) release();
3920 //*********************************************************************************
3921 // [private] stop_ack_timer
3922 //*********************************************************************************
3924 void IOService::stop_ack_timer ( void )
3928 pending
= thread_call_cancel(fAckTimer
);
3929 if (pending
) release();
3932 //*********************************************************************************
3933 // [static] settleTimerExpired
3935 // Inside PM work loop's gate.
3936 //*********************************************************************************
3939 IOService::actionAckTimerExpired (
3941 void * arg0
, void * arg1
,
3942 void * arg2
, void * arg3
)
3944 IOService
* me
= (IOService
*) target
;
3947 // done will be true if the timer tick unblocks the machine state,
3948 // otherwise no need to signal the work loop.
3950 done
= me
->ackTimerTick();
3951 if (done
&& gIOPMReplyQueue
)
3952 gIOPMReplyQueue
->signalWorkAvailable();
3954 return kIOReturnSuccess
;
3957 //*********************************************************************************
3958 // ack_timer_expired
3960 // Thread call function. Holds a retain while the callout is in flight.
3961 //*********************************************************************************
3964 IOService::ack_timer_expired ( thread_call_param_t arg0
, thread_call_param_t arg1
)
3966 IOService
* me
= (IOService
*) arg0
;
3970 gIOPMWorkLoop
->runAction(&actionAckTimerExpired
, me
);
3975 //*********************************************************************************
3976 // settleTimerExpired
3978 // Inside PM work loop's gate.
3979 //*********************************************************************************
3982 settleTimerExpired (
3984 void * arg0
, void * arg1
,
3985 void * arg2
, void * arg3
)
3987 IOService
* me
= (IOService
*) target
;
3988 me
->settleTimerExpired();
3989 return kIOReturnSuccess
;
3992 //*********************************************************************************
3993 // settle_timer_expired
3995 // Thread call function. Holds a retain while the callout is in flight.
3996 //*********************************************************************************
3999 settle_timer_expired ( thread_call_param_t arg0
, thread_call_param_t arg1
)
4001 IOService
* me
= (IOService
*) arg0
;
4003 if (gIOPMWorkLoop
&& gIOPMReplyQueue
)
4005 gIOPMWorkLoop
->runAction(settleTimerExpired
, me
);
4006 gIOPMReplyQueue
->signalWorkAvailable();
4011 //*********************************************************************************
4012 // [private] start_parent_change
4014 // Here we begin the processing of a power change initiated by our parent.
4015 //*********************************************************************************
4017 IOReturn
IOService::start_parent_change ( const changeNoteItem
* changeNote
)
4019 fHeadNoteFlags
= changeNote
->flags
;
4020 fHeadNoteState
= changeNote
->newStateNumber
;
4021 fHeadNoteOutputFlags
= changeNote
->outputPowerCharacter
;
4022 fHeadNoteDomainState
= changeNote
->domainState
;
4023 fHeadNoteParent
= changeNote
->parent
;
4024 fHeadNoteCapabilityFlags
= changeNote
->capabilityFlags
;
4026 PM_ASSERT_IN_GATE();
4027 OUR_PMLog( kPMLogStartParentChange
, fHeadNoteState
, fCurrentPowerState
);
4029 // Power domain is lowering power
4030 if ( fHeadNoteState
< fCurrentPowerState
)
4033 changeNote
->singleParentState
,
4034 fHeadNoteParent
, true );
4036 // tell apps and kernel clients
4037 fInitialChange
= false;
4038 fMachineState
= kIOPM_ParentDownTellPriorityClientsPowerDown
;
4039 tellChangeDown1(fHeadNoteState
);
4040 return IOPMWillAckLater
;
4043 // Power domain is raising power
4044 if ( fHeadNoteState
> fCurrentPowerState
)
4046 IOPMPowerState
* powerStatePtr
;
4048 if ( fDesiredPowerState
> fCurrentPowerState
)
4050 if ( fDesiredPowerState
< fHeadNoteState
)
4052 // We power up, but not all the way
4053 fHeadNoteState
= fDesiredPowerState
;
4054 powerStatePtr
= &fPowerStates
[fHeadNoteState
];
4055 fHeadNoteOutputFlags
= powerStatePtr
->outputPowerCharacter
;
4056 fHeadNoteCapabilityFlags
= powerStatePtr
->capabilityFlags
;
4057 OUR_PMLog(kPMLogAmendParentChange
, fHeadNoteState
, 0);
4060 // We don't need to change
4061 fHeadNoteState
= fCurrentPowerState
;
4062 powerStatePtr
= &fPowerStates
[fHeadNoteState
];
4063 fHeadNoteOutputFlags
= powerStatePtr
->outputPowerCharacter
;
4064 fHeadNoteCapabilityFlags
= powerStatePtr
->capabilityFlags
;
4065 OUR_PMLog(kPMLogAmendParentChange
, fHeadNoteState
, 0);
4069 if ((fHeadNoteState
> fCurrentPowerState
) &&
4070 (fHeadNoteFlags
& IOPMDomainDidChange
))
4072 // Parent did change up - start our change up
4073 fInitialChange
= false;
4074 fMachineState
= kIOPM_ParentUpSetPowerState
;
4076 return IOPMWillAckLater
;
4080 return IOPMAckImplied
;
4083 //*********************************************************************************
4084 // [private] start_our_change
4086 // Here we begin the processing of a power change initiated by us.
4087 //*********************************************************************************
4089 void IOService::start_our_change ( const changeNoteItem
* changeNote
)
4091 fHeadNoteFlags
= changeNote
->flags
;
4092 fHeadNoteState
= changeNote
->newStateNumber
;
4093 fHeadNoteOutputFlags
= changeNote
->outputPowerCharacter
;
4094 fHeadNoteCapabilityFlags
= changeNote
->capabilityFlags
;
4096 PM_ASSERT_IN_GATE();
4098 OUR_PMLog( kPMLogStartDeviceChange
, fHeadNoteState
, fCurrentPowerState
);
4100 // can our driver switch to the new state?
4101 if (( fHeadNoteCapabilityFlags
& IOPMNotAttainable
) ||
4102 ((fMaxCapability
< fHeadNoteState
) && (!fWeAreRoot
)))
4104 // mark the change note un-actioned
4105 fHeadNoteFlags
|= IOPMNotDone
;
4107 // no, ask the parent to do it then
4110 ask_parent(fHeadNoteState
);
4116 if ( !fInitialChange
)
4118 if ( fHeadNoteState
== fCurrentPowerState
)
4120 // we initiated a null change; forget it
4125 fInitialChange
= false;
4128 if ( fHeadNoteState
< fCurrentPowerState
)
4130 // yes, in case we have to wait for acks
4131 fMachineState
= kIOPM_OurChangeTellClientsPowerDown
;
4132 fDoNotPowerDown
= false;
4134 // ask apps and kernel clients if we can drop power
4135 fOutOfBandParameter
= kNotifyApps
;
4136 askChangeDown(fHeadNoteState
);
4138 // in case they don't all ack
4139 fMachineState
= kIOPM_OurChangeSetPowerState
;
4140 // notify interested drivers and children
4145 //*********************************************************************************
4146 // [private] ask_parent
4148 // Call the power domain parent to ask for a higher power state in the domain
4149 // or to suggest a lower power state.
4150 //*********************************************************************************
4152 IOReturn
IOService::ask_parent ( unsigned long requestedState
)
4156 IOPowerConnection
* connection
;
4158 const IOPMPowerState
* powerStatePtr
;
4159 unsigned long ourRequest
;
4161 PM_ASSERT_IN_GATE();
4162 if (requestedState
>= fNumberOfPowerStates
)
4165 powerStatePtr
= &fPowerStates
[requestedState
];
4166 ourRequest
= powerStatePtr
->inputPowerRequirement
;
4168 if ( powerStatePtr
->capabilityFlags
& (kIOPMChildClamp
| kIOPMPreventIdleSleep
) )
4170 ourRequest
|= kIOPMPreventIdleSleep
;
4172 if ( powerStatePtr
->capabilityFlags
& (kIOPMChildClamp2
| kIOPMPreventSystemSleep
) )
4174 ourRequest
|= kIOPMPreventSystemSleep
;
4177 // is this a new desire?
4178 if ( fPreviousRequest
== ourRequest
)
4180 // no, the parent knows already, just return
4188 fPreviousRequest
= ourRequest
;
4190 iter
= getParentIterator(gIOPowerPlane
);
4193 while ( (next
= iter
->getNextObject()) )
4195 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
4197 parent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
4199 if ( parent
->requestPowerDomainState(
4200 ourRequest
, connection
, IOPMLowestState
) != IOPMNoErr
)
4202 OUR_PMLog(kPMLogRequestDenied
, fPreviousRequest
, 0);
4214 //*********************************************************************************
4215 // [private] notifyControllingDriver
4216 //*********************************************************************************
4218 bool IOService::notifyControllingDriver ( void )
4220 DriverCallParam
* param
;
4221 unsigned long powerState
;
4223 PM_ASSERT_IN_GATE();
4224 assert( fDriverCallBusy
== false );
4225 assert( fDriverCallParamCount
== 0 );
4226 assert( fControllingDriver
);
4228 powerState
= fHeadNoteState
;
4229 if (fPowerStates
[powerState
].capabilityFlags
& IOPMNotAttainable
)
4230 return false; // state not attainable
4232 param
= (DriverCallParam
*) fDriverCallParamPtr
;
4235 param
= IONew(DriverCallParam
, 1);
4237 return false; // no memory
4239 fDriverCallParamPtr
= (void *) param
;
4240 fDriverCallParamSlots
= 1;
4243 param
->Target
= fControllingDriver
;
4244 fDriverCallParamCount
= 1;
4248 // Machine state for this object will stall waiting for a reply
4249 // from the callout thread.
4252 fDriverCallBusy
= true;
4254 thread_call_enter( fDriverCallEntry
);
4258 //*********************************************************************************
4259 // [private] notifyControllingDriverDone
4260 //*********************************************************************************
4262 void IOService::notifyControllingDriverDone( void )
4264 DriverCallParam
* param
;
4267 PM_ASSERT_IN_GATE();
4268 param
= (DriverCallParam
*) fDriverCallParamPtr
;
4270 assert( fDriverCallBusy
== false );
4271 assert( fMachineState
== kIOPM_DriverThreadCallDone
);
4275 assert(fDriverCallParamCount
== 1);
4277 // the return value from setPowerState()
4278 result
= param
->Result
;
4280 if ((result
== IOPMAckImplied
) || (result
< 0))
4282 // child return IOPMAckImplied
4285 else if (fDriverTimer
)
4287 assert(fDriverTimer
== -1);
4289 // Driver has not acked, and has returned a positive result.
4290 // Enforce a minimum permissible timeout value.
4291 // Make the min value large enough so timeout is less likely
4292 // to occur if a driver misinterpreted that the return value
4293 // should be in microsecond units. And make it large enough
4294 // to be noticeable if a driver neglects to ack.
4296 if (result
< kMinAckTimeoutTicks
)
4297 result
= kMinAckTimeoutTicks
;
4299 fDriverTimer
= (result
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
4301 // else, child has already acked and driver_timer reset to 0.
4303 fDriverCallParamCount
= 0;
4307 OUR_PMLog(kPMLogStartAckTimer
, 0, 0);
4312 // Hop back to original machine state path.
4313 fMachineState
= fNextMachineState
;
4316 //*********************************************************************************
4317 // [public virtual] askChangeDown
4319 // Ask registered applications and kernel clients if we can change to a lower
4322 // Subclass can override this to send a different message type. Parameter is
4323 // the destination state number.
4325 // Return true if we don't have to wait for acknowledgements
4326 //*********************************************************************************
4328 bool IOService::askChangeDown ( unsigned long stateNum
)
4330 return tellClientsWithResponse( kIOMessageCanDevicePowerOff
);
4333 //*********************************************************************************
4334 // [public] tellChangeDown1
4336 // Notify registered applications and kernel clients that we are definitely
4339 // Return true if we don't have to wait for acknowledgements
4340 //*********************************************************************************
4342 bool IOService::tellChangeDown1 ( unsigned long stateNum
)
4344 fOutOfBandParameter
= kNotifyApps
;
4345 return tellChangeDown(stateNum
);
4348 //*********************************************************************************
4349 // [public] tellChangeDown2
4351 // Notify priority clients that we are definitely dropping power.
4353 // Return true if we don't have to wait for acknowledgements
4354 //*********************************************************************************
4356 bool IOService::tellChangeDown2 ( unsigned long stateNum
)
4358 fOutOfBandParameter
= kNotifyPriority
;
4359 return tellChangeDown(stateNum
);
4362 //*********************************************************************************
4363 // [public virtual] tellChangeDown
4365 // Notify registered applications and kernel clients that we are definitely
4368 // Subclass can override this to send a different message type. Parameter is
4369 // the destination state number.
4371 // Return true if we don't have to wait for acknowledgements
4372 //*********************************************************************************
4374 bool IOService::tellChangeDown ( unsigned long stateNum
)
4376 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff
);
4379 //*********************************************************************************
4380 // cleanClientResponses
4382 //*********************************************************************************
4384 static void logAppTimeouts ( OSObject
* object
, void * context
)
4386 struct context
*theContext
= (struct context
*)context
;
4389 if( !OSDynamicCast( IOService
, object
) ) {
4390 flag
= theContext
->responseFlags
->getObject(theContext
->counter
);
4391 if (kOSBooleanTrue
!= flag
)
4393 OSString
* clientID
= 0;
4394 theContext
->us
->messageClient(theContext
->msgType
, object
, &clientID
);
4395 PM_ERROR(theContext
->errorLog
, clientID
? clientID
->getCStringNoCopy() : "");
4397 clientID
->release();
4399 theContext
->counter
+= 1;
4403 void IOService::cleanClientResponses ( bool logErrors
)
4405 struct context theContext
;
4407 if (logErrors
&& fResponseArray
) {
4408 theContext
.responseFlags
= fResponseArray
;
4409 theContext
.serialNumber
= fSerialNumber
;
4410 theContext
.counter
= 0;
4411 theContext
.msgType
= kIOMessageCopyClientID
;
4412 theContext
.us
= this;
4413 theContext
.maxTimeRequested
= 0;
4414 theContext
.stateNumber
= fHeadNoteState
;
4415 theContext
.stateFlags
= fHeadNoteCapabilityFlags
;
4416 theContext
.errorLog
= "PM notification timeout (%s)\n";
4418 switch ( fOutOfBandParameter
) {
4420 applyToInterested(gIOAppPowerStateInterest
, logAppTimeouts
, (void *) &theContext
);
4421 case kNotifyPriority
:
4429 // get rid of this stuff
4430 fResponseArray
->release();
4431 fResponseArray
= NULL
;
4437 //*********************************************************************************
4438 // [public] tellClientsWithResponse
4440 // Notify registered applications and kernel clients that we are definitely
4443 // Return true if we don't have to wait for acknowledgements
4444 //*********************************************************************************
4446 bool IOService::tellClientsWithResponse ( int messageType
)
4448 struct context theContext
;
4450 PM_ASSERT_IN_GATE();
4452 fResponseArray
= OSArray::withCapacity( 1 );
4455 theContext
.responseFlags
= fResponseArray
;
4456 theContext
.serialNumber
= fSerialNumber
;
4457 theContext
.counter
= 0;
4458 theContext
.msgType
= messageType
;
4459 theContext
.us
= this;
4460 theContext
.maxTimeRequested
= 0;
4461 theContext
.stateNumber
= fHeadNoteState
;
4462 theContext
.stateFlags
= fHeadNoteCapabilityFlags
;
4464 switch ( fOutOfBandParameter
) {
4466 applyToInterested(gIOAppPowerStateInterest
,
4467 pmTellAppWithResponse
, (void *)&theContext
);
4468 applyToInterested(gIOGeneralInterest
,
4469 pmTellClientWithResponse
, (void *)&theContext
);
4471 case kNotifyPriority
:
4472 applyToInterested(gIOPriorityPowerStateInterest
,
4473 pmTellClientWithResponse
, (void *)&theContext
);
4477 // do we have to wait for somebody?
4478 if ( !checkForDone() )
4480 OUR_PMLog(kPMLogStartAckTimer
,theContext
.maxTimeRequested
, 0);
4481 start_ack_timer( theContext
.maxTimeRequested
/ 1000, kMillisecondScale
);
4485 // everybody responded
4486 fResponseArray
->release();
4487 fResponseArray
= NULL
;
4488 // cleanClientResponses(false);
4493 //*********************************************************************************
4494 // [static private] pmTellAppWithResponse
4496 // We send a message to an application, and we expect a response, so we compute a
4497 // cookie we can identify the response with.
4498 //*********************************************************************************
4500 void IOService::pmTellAppWithResponse ( OSObject
* object
, void * context
)
4502 struct context
* theContext
= (struct context
*) context
;
4503 IOServicePM
* pwrMgt
= theContext
->us
->pwrMgt
;
4506 if( OSDynamicCast( IOService
, object
) )
4508 // Automatically 'ack' in kernel clients
4509 theContext
->responseFlags
->setObject(theContext
->counter
, kOSBooleanTrue
);
4511 const char *who
= ((IOService
*) object
)->getName();
4512 fPlatform
->PMLog(who
,
4513 kPMLogClientAcknowledge
, theContext
->msgType
, * (UInt32
*) object
);
4515 UInt32 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16)
4516 + (theContext
->counter
& 0xFFFF);
4517 OUR_PMLog(kPMLogAppNotify
, theContext
->msgType
, refcon
);
4519 #if LOG_APP_RESPONSE_TIMES
4521 clock_get_uptime(&now
);
4522 num
= OSNumber::withNumber(AbsoluteTime_to_scalar(&now
), sizeof(uint64_t) * 8);
4525 theContext
->responseFlags
->setObject(theContext
->counter
, num
);
4530 theContext
->responseFlags
->setObject(theContext
->counter
, kOSBooleanFalse
);
4532 theContext
->us
->messageClient(theContext
->msgType
, object
, (void *)refcon
);
4533 if ( theContext
->maxTimeRequested
< k30seconds
)
4535 theContext
->maxTimeRequested
= k30seconds
;
4538 theContext
->counter
+= 1;
4542 //*********************************************************************************
4543 // [static private] pmTellClientWithResponse
4545 // We send a message to an in-kernel client, and we expect a response, so we compute a
4546 // cookie we can identify the response with.
4547 // If it doesn't understand the notification (it is not power-management savvy)
4548 // we won't wait for it to prepare for sleep. If it tells us via a return code
4549 // in the passed struct that it is currently ready, we won't wait for it to prepare.
4550 // If it tells us via the return code in the struct that it does need time, we will chill.
4551 //*********************************************************************************
4553 void IOService::pmTellClientWithResponse ( OSObject
* object
, void * context
)
4555 struct context
*theContext
= (struct context
*)context
;
4556 IOPowerStateChangeNotification notify
;
4561 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
4562 theContext
->responseFlags
->setObject(theContext
->counter
, kOSBooleanFalse
);
4564 IOServicePM
* pwrMgt
= theContext
->us
->pwrMgt
;
4565 if (gIOKitDebug
& kIOLogPower
) {
4566 OUR_PMLog(kPMLogClientNotify
, refcon
, (UInt32
) theContext
->msgType
);
4567 if (OSDynamicCast(IOService
, object
)) {
4568 const char *who
= ((IOService
*) object
)->getName();
4569 fPlatform
->PMLog(who
,
4570 kPMLogClientNotify
, * (UInt32
*) object
, (UInt32
) object
);
4571 } else if (OSDynamicCast(_IOServiceInterestNotifier
, object
)) {
4572 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
4573 OUR_PMLog(kPMLogClientNotify
, (UInt32
) n
->handler
, 0);
4577 notify
.powerRef
= (void *)refcon
;
4578 notify
.returnValue
= 0;
4579 notify
.stateNumber
= theContext
->stateNumber
;
4580 notify
.stateFlags
= theContext
->stateFlags
;
4581 retCode
= theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)¬ify
);
4582 if ( retCode
== kIOReturnSuccess
)
4584 if ( notify
.returnValue
== 0 )
4586 // client doesn't want time to respond
4587 theContext
->responseFlags
->replaceObject(theContext
->counter
, kOSBooleanTrue
);
4588 OUR_PMLog(kPMLogClientAcknowledge
, refcon
, (UInt32
) object
);
4590 // it does want time, and it hasn't responded yet
4591 theFlag
= theContext
->responseFlags
->getObject(theContext
->counter
);
4592 if ( kOSBooleanTrue
!= theFlag
)
4594 // so note its time requirement
4595 if ( theContext
->maxTimeRequested
< notify
.returnValue
)
4597 theContext
->maxTimeRequested
= notify
.returnValue
;
4602 OUR_PMLog(kPMLogClientAcknowledge
, refcon
, 0);
4603 // not a client of ours
4604 // so we won't be waiting for response
4605 theContext
->responseFlags
->replaceObject(theContext
->counter
, kOSBooleanTrue
);
4607 theContext
->counter
+= 1;
4610 //*********************************************************************************
4611 // [public virtual] tellNoChangeDown
4613 // Notify registered applications and kernel clients that we are not
4616 // Subclass can override this to send a different message type. Parameter is
4617 // the aborted destination state number.
4618 //*********************************************************************************
4620 void IOService::tellNoChangeDown ( unsigned long )
4622 return tellClients( kIOMessageDeviceWillNotPowerOff
);
4625 //*********************************************************************************
4626 // [public virtual] tellChangeUp
4628 // Notify registered applications and kernel clients that we are raising power.
4630 // Subclass can override this to send a different message type. Parameter is
4631 // the aborted destination state number.
4632 //*********************************************************************************
4634 void IOService::tellChangeUp ( unsigned long )
4636 return tellClients( kIOMessageDeviceHasPoweredOn
);
4639 //*********************************************************************************
4640 // [public] tellClients
4642 // Notify registered applications and kernel clients of something.
4643 //*********************************************************************************
4645 void IOService::tellClients ( int messageType
)
4647 struct context theContext
;
4649 theContext
.msgType
= messageType
;
4650 theContext
.us
= this;
4651 theContext
.stateNumber
= fHeadNoteState
;
4652 theContext
.stateFlags
= fHeadNoteCapabilityFlags
;
4654 applyToInterested(gIOPriorityPowerStateInterest
,tellClient
,(void *)&theContext
);
4655 applyToInterested(gIOAppPowerStateInterest
,tellClient
, (void *)&theContext
);
4656 applyToInterested(gIOGeneralInterest
,tellClient
, (void *)&theContext
);
4659 //*********************************************************************************
4660 // [global] tellClient
4662 // Notify a registered application or kernel client of something.
4663 //*********************************************************************************
4665 void tellClient ( OSObject
* object
, void * context
)
4667 struct context
* theContext
= (struct context
*) context
;
4668 IOPowerStateChangeNotification notify
;
4670 notify
.powerRef
= (void *) 0;
4671 notify
.returnValue
= 0;
4672 notify
.stateNumber
= theContext
->stateNumber
;
4673 notify
.stateFlags
= theContext
->stateFlags
;
4675 theContext
->us
->messageClient(theContext
->msgType
, object
, ¬ify
);
4678 //*********************************************************************************
4679 // [private] checkForDone
4680 //*********************************************************************************
4682 bool IOService::checkForDone ( void )
4687 if ( fResponseArray
== NULL
)
4692 for ( i
= 0; ; i
++ )
4694 theFlag
= fResponseArray
->getObject(i
);
4695 if ( theFlag
== NULL
)
4699 if ( kOSBooleanTrue
!= theFlag
)
4707 //*********************************************************************************
4708 // [public] responseValid
4709 //*********************************************************************************
4711 bool IOService::responseValid ( unsigned long x
, int pid
)
4713 UInt16 serialComponent
;
4714 UInt16 ordinalComponent
;
4716 unsigned long refcon
= (unsigned long) x
;
4718 serialComponent
= (refcon
>> 16) & 0xFFFF;
4719 ordinalComponent
= (refcon
& 0xFFFF);
4721 if ( serialComponent
!= fSerialNumber
)
4726 if ( fResponseArray
== NULL
)
4731 theFlag
= fResponseArray
->getObject(ordinalComponent
);
4739 if ((num
= OSDynamicCast(OSNumber
, theFlag
)))
4741 #if LOG_APP_RESPONSE_TIMES
4746 clock_get_uptime(&now
);
4747 AbsoluteTime_to_scalar(&start
) = num
->unsigned64BitValue();
4748 SUB_ABSOLUTETIME(&now
, &start
);
4749 absolutetime_to_nanoseconds(now
, &nsec
);
4752 if (nsec
> LOG_APP_RESPONSE_TIMES
)
4754 OSString
* name
= IOCopyLogNameForPID(pid
);
4755 PM_DEBUG("PM response took %d ms (%s)\n", NS_TO_MS(nsec
),
4756 name
? name
->getCStringNoCopy() : "");
4761 theFlag
= kOSBooleanFalse
;
4764 if ( kOSBooleanFalse
== theFlag
)
4766 fResponseArray
->replaceObject(ordinalComponent
, kOSBooleanTrue
);
4772 //*********************************************************************************
4773 // [public virtual] allowPowerChange
4775 // Our power state is about to lower, and we have notified applications
4776 // and kernel clients, and one of them has acknowledged. If this is the last to do
4777 // so, and all acknowledgements are positive, we continue with the power change.
4779 // We serialize this processing with timer expiration with a command gate on the
4780 // power management workloop, which the timer expiration is command gated to as well.
4781 //*********************************************************************************
4783 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
4785 IOPMRequest
* request
;
4790 return kIOReturnSuccess
;
4793 request
= acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange
);
4796 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__
);
4797 return kIOReturnNoMemory
;
4800 request
->fArg0
= (void *) refcon
;
4801 request
->fArg1
= (void *) proc_selfpid();
4802 submitPMRequest( request
);
4804 return kIOReturnSuccess
;
4807 IOReturn
serializedAllowPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
4809 // [deprecated] public
4810 return kIOReturnUnsupported
;
4813 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
4815 // [deprecated] public
4816 return kIOReturnUnsupported
;
4819 //*********************************************************************************
4820 // [public virtual] cancelPowerChange
4822 // Our power state is about to lower, and we have notified applications
4823 // and kernel clients, and one of them has vetoed the change. If this is the last
4824 // client to respond, we abandon the power change.
4826 // We serialize this processing with timer expiration with a command gate on the
4827 // power management workloop, which the timer expiration is command gated to as well.
4828 //*********************************************************************************
4830 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
4832 IOPMRequest
* request
;
4837 return kIOReturnSuccess
;
4840 request
= acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange
);
4843 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__
);
4844 return kIOReturnNoMemory
;
4847 request
->fArg0
= (void *) refcon
;
4848 request
->fArg1
= (void *) proc_selfpid();
4849 submitPMRequest( request
);
4851 return kIOReturnSuccess
;
4854 IOReturn
serializedCancelPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
4856 // [deprecated] public
4857 return kIOReturnUnsupported
;
4860 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
4862 // [deprecated] public
4863 return kIOReturnUnsupported
;
4867 //*********************************************************************************
4868 // c_PM_clamp_Timer_Expired (C Func)
4870 // Called when our clamp timer expires...we will call the object method.
4871 //*********************************************************************************
4873 static void c_PM_Clamp_Timer_Expired ( OSObject
* client
, IOTimerEventSource
* )
4876 ((IOService
*)client
)->PM_Clamp_Timer_Expired ();
4880 //*********************************************************************************
4881 // PM_Clamp_Timer_Expired
4883 // called when clamp timer expires...set power state to 0.
4884 //*********************************************************************************
4886 void IOService::PM_Clamp_Timer_Expired ( void )
4889 if ( ! initialized
)
4895 changePowerStateToPriv (0);
4899 //*********************************************************************************
4902 // Set to highest available power state for a minimum of duration milliseconds
4903 //*********************************************************************************
4905 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
4907 void IOService::clampPowerOn ( unsigned long duration
)
4910 changePowerStateToPriv (fNumberOfPowerStates
-1);
4912 if ( pwrMgt
->clampTimerEventSrc
== NULL
) {
4913 pwrMgt
->clampTimerEventSrc
= IOTimerEventSource::timerEventSource(this,
4914 c_PM_Clamp_Timer_Expired
);
4916 IOWorkLoop
* workLoop
= getPMworkloop ();
4918 if ( !pwrMgt
->clampTimerEventSrc
|| !workLoop
||
4919 ( workLoop
->addEventSource( pwrMgt
->clampTimerEventSrc
) != kIOReturnSuccess
) ) {
4924 pwrMgt
->clampTimerEventSrc
->setTimeout(300*USEC_PER_SEC
, USEC_PER_SEC
);
4928 //*********************************************************************************
4929 // [public virtual] setPowerState
4931 // Does nothing here. This should be implemented in a subclass driver.
4932 //*********************************************************************************
4934 IOReturn
IOService::setPowerState (
4935 unsigned long powerStateOrdinal
, IOService
* whatDevice
)
4940 //*********************************************************************************
4941 // [public virtual] maxCapabilityForDomainState
4943 // Finds the highest power state in the array whose input power
4944 // requirement is equal to the input parameter. Where a more intelligent
4945 // decision is possible, override this in the subclassed driver.
4946 //*********************************************************************************
4948 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
4952 if (fNumberOfPowerStates
== 0 )
4956 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
4958 if ( (domainState
& fPowerStates
[i
].inputPowerRequirement
) ==
4959 fPowerStates
[i
].inputPowerRequirement
)
4967 //*********************************************************************************
4968 // [public virtual] initialPowerStateForDomainState
4970 // Finds the highest power state in the array whose input power
4971 // requirement is equal to the input parameter. Where a more intelligent
4972 // decision is possible, override this in the subclassed driver.
4973 //*********************************************************************************
4975 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
4979 if (fNumberOfPowerStates
== 0 )
4983 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
4985 if ( (domainState
& fPowerStates
[i
].inputPowerRequirement
) ==
4986 fPowerStates
[i
].inputPowerRequirement
)
4994 //*********************************************************************************
4995 // [public virtual] powerStateForDomainState
4997 // Finds the highest power state in the array whose input power
4998 // requirement is equal to the input parameter. Where a more intelligent
4999 // decision is possible, override this in the subclassed driver.
5000 //*********************************************************************************
5002 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
5006 if (fNumberOfPowerStates
== 0 )
5010 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
5012 if ( (domainState
& fPowerStates
[i
].inputPowerRequirement
) ==
5013 fPowerStates
[i
].inputPowerRequirement
)
5021 //*********************************************************************************
5022 // [public virtual] didYouWakeSystem
5024 // Does nothing here. This should be implemented in a subclass driver.
5025 //*********************************************************************************
5027 bool IOService::didYouWakeSystem ( void )
5032 //*********************************************************************************
5033 // [public virtual] powerStateWillChangeTo
5035 // Does nothing here. This should be implemented in a subclass driver.
5036 //*********************************************************************************
5038 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
* )
5040 return kIOPMAckImplied
;
5043 //*********************************************************************************
5044 // [public virtual] powerStateDidChangeTo
5046 // Does nothing here. This should be implemented in a subclass driver.
5047 //*********************************************************************************
5049 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
* )
5051 return kIOPMAckImplied
;
5054 //*********************************************************************************
5055 // [public virtual] powerChangeDone
5057 // Called from PM work loop thread.
5058 // Does nothing here. This should be implemented in a subclass policy-maker.
5059 //*********************************************************************************
5061 void IOService::powerChangeDone ( unsigned long )
5065 //*********************************************************************************
5066 // [public virtual] newTemperature
5068 // Does nothing here. This should be implemented in a subclass driver.
5069 //*********************************************************************************
5071 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
5076 //*********************************************************************************
5077 // [public virtual] systemWillShutdown
5079 // System shutdown and restart notification.
5080 //*********************************************************************************
5082 void IOService::systemWillShutdown( IOOptionBits specifier
)
5084 IOPMrootDomain
* rootDomain
= IOService::getPMRootDomain();
5086 rootDomain
->acknowledgeSystemWillShutdown( this );
5089 //*********************************************************************************
5090 // [private static] acquirePMRequest
5091 //*********************************************************************************
5094 IOService::acquirePMRequest( IOService
* target
, IOOptionBits requestType
)
5096 IOPMRequest
* request
;
5100 request
= IOPMRequest::create();
5103 request
->init( target
, requestType
);
5108 //*********************************************************************************
5109 // [private static] releasePMRequest
5110 //*********************************************************************************
5112 void IOService::releasePMRequest( IOPMRequest
* request
)
5121 //*********************************************************************************
5122 // [private] submitPMRequest
5123 //*********************************************************************************
5125 void IOService::submitPMRequest( IOPMRequest
* request
)
5128 assert( gIOPMReplyQueue
);
5129 assert( gIOPMRequestQueue
);
5131 PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
5132 request
->getType(), request
,
5133 request
->getTarget(), request
->getTarget()->getName(),
5134 request
->fArg0
, request
->fArg1
, request
->fArg2
);
5136 if (request
->isReply())
5137 gIOPMReplyQueue
->queuePMRequest( request
);
5139 gIOPMRequestQueue
->queuePMRequest( request
);
5142 void IOService::submitPMRequest( IOPMRequest
** requests
, IOItemCount count
)
5145 assert( count
> 0 );
5146 assert( gIOPMRequestQueue
);
5148 for (IOItemCount i
= 0; i
< count
; i
++)
5150 IOPMRequest
* req
= requests
[i
];
5151 PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
5152 req
->getType(), req
,
5153 req
->getTarget(), req
->getTarget()->getName(),
5154 req
->fArg0
, req
->fArg1
, req
->fArg2
);
5157 gIOPMRequestQueue
->queuePMRequestChain( requests
, count
);
5160 //*********************************************************************************
5161 // [private] servicePMRequestQueue
5162 //*********************************************************************************
5164 bool IOService::servicePMRequestQueue(
5165 IOPMRequest
* request
,
5166 IOPMRequestQueue
* queue
)
5168 // Calling PM methods without PMinit() is not allowed, fail the requests.
5172 PM_DEBUG("[%s] %s: PM not initialized\n", getName(), __FUNCTION__
);
5176 // Create an IOPMWorkQueue on demand, when the initial PM request is
5181 // Allocate and attach an IOPMWorkQueue on demand to avoid taking
5182 // the work loop lock in PMinit(), which may deadlock with certain
5183 // drivers / families.
5185 fPMWorkQueue
= IOPMWorkQueue::create(
5187 /* Work */ OSMemberFunctionCast(IOPMWorkQueue::Action
, this,
5188 &IOService::servicePMRequest
),
5189 /* Done */ OSMemberFunctionCast(IOPMWorkQueue::Action
, this,
5190 &IOService::retirePMRequest
)
5194 (gIOPMWorkLoop
->addEventSource(fPMWorkQueue
) != kIOReturnSuccess
))
5196 PM_ERROR("[%s] %s: addEventSource failed\n",
5197 getName(), __FUNCTION__
);
5198 fPMWorkQueue
->release();
5204 PM_ERROR("[%s] %s: not ready (type %02lx)\n",
5205 getName(), __FUNCTION__
, request
->getType());
5210 fPMWorkQueue
->queuePMRequest(request
);
5211 return false; // do not signal more
5214 gIOPMFreeQueue
->queuePMRequest( request
);
5215 return false; // do not signal more
5218 //*********************************************************************************
5219 // [private] servicePMFreeQueue
5221 // Called by IOPMFreeQueue to recycle a completed request.
5222 //*********************************************************************************
5224 bool IOService::servicePMFreeQueue(
5225 IOPMRequest
* request
,
5226 IOPMRequestQueue
* queue
)
5228 bool more
= request
->hasParentRequest();
5229 releasePMRequest( request
);
5233 //*********************************************************************************
5234 // [private] retirePMRequest
5236 // Called by IOPMWorkQueue to retire a completed request.
5237 //*********************************************************************************
5239 bool IOService::retirePMRequest( IOPMRequest
* request
, IOPMWorkQueue
* queue
)
5241 assert(request
&& queue
);
5243 PM_TRACE("[- %02lx] %p [%p %s] State %ld, Busy %ld\n",
5244 request
->getType(), request
, this, getName(),
5245 fMachineState
, gIOPMBusyCount
);
5247 // Catch requests created by PM_idle_timer_expiration().
5249 if ((request
->getType() == kIOPMRequestTypeActivityTickle
) &&
5250 (request
->fArg1
== (void *) false))
5252 // Idle timer power drop request completed.
5253 // Restart the idle timer if deviceDesire can go lower, otherwise set
5254 // a flag so we know to restart idle timer when deviceDesire goes up.
5256 if (fDeviceDesire
> 0)
5257 start_PM_idle_timer();
5259 fActivityTimerStopped
= true;
5262 gIOPMFreeQueue
->queuePMRequest( request
);
5266 //*********************************************************************************
5267 // [private] isPMBlocked
5269 // Check if machine state transition is blocked.
5270 //*********************************************************************************
5272 bool IOService::isPMBlocked ( IOPMRequest
* request
, int count
)
5277 if (kIOPM_Finished
== fMachineState
)
5280 if (kIOPM_DriverThreadCallDone
== fMachineState
)
5282 // 5 = kDriverCallInformPreChange
5283 // 6 = kDriverCallInformPostChange
5284 // 7 = kDriverCallSetPowerState
5285 if (fDriverCallBusy
) reason
= 5 + fDriverCallReason
;
5289 // Waiting on driver's setPowerState() timeout.
5295 // Child or interested driver acks pending.
5296 if (fHeadNotePendingAcks
)
5301 // Waiting on apps or priority power interest clients.
5307 // Waiting on settle timer expiration.
5314 fWaitReason
= reason
;
5320 PM_TRACE("[B %02lx] %p [%p %s] State %ld, Reason %d\n",
5321 request
->getType(), request
, this, getName(),
5322 fMachineState
, reason
);
5331 //*********************************************************************************
5332 // [private] servicePMRequest
5334 // Service a request from our work queue.
5335 //*********************************************************************************
5337 bool IOService::servicePMRequest( IOPMRequest
* request
, IOPMWorkQueue
* queue
)
5342 assert(request
&& queue
);
5344 while (isPMBlocked(request
, loop
++) == false)
5346 PM_TRACE("[W %02lx] %p [%p %s] State %ld\n",
5347 request
->getType(), request
, this, getName(), fMachineState
);
5349 fPMRequest
= request
;
5351 // Every PM machine states must be handled in one of the cases below.
5353 switch ( fMachineState
)
5355 case kIOPM_Finished
:
5356 executePMRequest( request
);
5359 case kIOPM_OurChangeTellClientsPowerDown
:
5360 // our change, was it vetoed?
5361 if (fDesiredPowerState
> fHeadNoteState
)
5363 PM_DEBUG("%s: idle cancel\n", fName
);
5364 fDoNotPowerDown
= true;
5366 if (!fDoNotPowerDown
)
5368 // no, we can continue
5369 OurChangeTellClientsPowerDown();
5373 // yes, rescind the warning
5374 tellNoChangeDown(fHeadNoteState
);
5375 // mark the change note un-actioned
5376 fHeadNoteFlags
|= IOPMNotDone
;
5382 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
5383 OurChangeTellPriorityClientsPowerDown();
5386 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
5387 OurChangeNotifyInterestedDriversWillChange();
5390 case kIOPM_OurChangeSetPowerState
:
5391 OurChangeSetPowerState();
5394 case kIOPM_OurChangeWaitForPowerSettle
:
5395 OurChangeWaitForPowerSettle();
5398 case kIOPM_OurChangeNotifyInterestedDriversDidChange
:
5399 OurChangeNotifyInterestedDriversDidChange();
5402 case kIOPM_OurChangeFinish
:
5406 case kIOPM_ParentDownTellPriorityClientsPowerDown
:
5407 ParentDownTellPriorityClientsPowerDown();
5410 case kIOPM_ParentDownNotifyInterestedDriversWillChange
:
5411 ParentDownNotifyInterestedDriversWillChange();
5414 case kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange
:
5415 ParentDownNotifyDidChangeAndAcknowledgeChange();
5418 case kIOPM_ParentDownSetPowerState
:
5419 ParentDownSetPowerState();
5422 case kIOPM_ParentDownWaitForPowerSettle
:
5423 ParentDownWaitForPowerSettle();
5426 case kIOPM_ParentDownAcknowledgeChange
:
5427 ParentDownAcknowledgeChange();
5430 case kIOPM_ParentUpSetPowerState
:
5431 ParentUpSetPowerState();
5434 case kIOPM_ParentUpWaitForSettleTime
:
5435 ParentUpWaitForSettleTime();
5438 case kIOPM_ParentUpNotifyInterestedDriversDidChange
:
5439 ParentUpNotifyInterestedDriversDidChange();
5442 case kIOPM_ParentUpAcknowledgePowerChange
:
5443 ParentUpAcknowledgePowerChange();
5446 case kIOPM_DriverThreadCallDone
:
5447 if (fDriverCallReason
== kDriverCallSetPowerState
)
5448 notifyControllingDriverDone();
5450 notifyInterestedDriversDone();
5453 case kIOPM_NotifyChildrenDone
:
5454 notifyChildrenDone();
5458 IOPanic("servicePMWorkQueue: unknown machine state");
5463 if (fMachineState
== kIOPM_Finished
)
5465 //PM_TRACE("[%s] PM End: Request %p (type %02lx)\n",
5466 // getName(), request, request->getType());
5475 //*********************************************************************************
5476 // [private] executePMRequest
5477 //*********************************************************************************
5479 void IOService::executePMRequest( IOPMRequest
* request
)
5481 assert( kIOPM_Finished
== fMachineState
);
5483 switch (request
->getType())
5485 case kIOPMRequestTypePMStop
:
5486 handlePMstop( request
);
5489 case kIOPMRequestTypeAddPowerChild1
:
5490 addPowerChild1( request
);
5493 case kIOPMRequestTypeAddPowerChild2
:
5494 addPowerChild2( request
);
5497 case kIOPMRequestTypeAddPowerChild3
:
5498 addPowerChild3( request
);
5501 case kIOPMRequestTypeRegisterPowerDriver
:
5502 handleRegisterPowerDriver( request
);
5505 case kIOPMRequestTypeAdjustPowerState
:
5509 case kIOPMRequestTypeMakeUsable
:
5510 handleMakeUsable( request
);
5513 case kIOPMRequestTypeTemporaryPowerClamp
:
5515 handleMakeUsable( request
);
5518 case kIOPMRequestTypePowerDomainWillChange
:
5519 handlePowerDomainWillChangeTo( request
);
5522 case kIOPMRequestTypePowerDomainDidChange
:
5523 handlePowerDomainDidChangeTo( request
);
5526 case kIOPMRequestTypeChangePowerStateTo
:
5527 handleChangePowerStateTo( request
);
5530 case kIOPMRequestTypeChangePowerStateToPriv
:
5531 handleChangePowerStateToPriv( request
);
5534 case kIOPMRequestTypePowerOverrideOnPriv
:
5535 case kIOPMRequestTypePowerOverrideOffPriv
:
5536 handlePowerOverrideChanged( request
);
5539 case kIOPMRequestTypeActivityTickle
:
5542 bool setDeviceDesire
= false;
5547 if (fDeviceDesire
< (unsigned long) request
->fArg0
)
5548 setDeviceDesire
= true;
5550 else if (fDeviceDesire
)
5552 // power drop and deviceDesire is not zero
5553 request
->fArg0
= (void *) (fDeviceDesire
- 1);
5554 setDeviceDesire
= true;
5557 if (setDeviceDesire
)
5559 // handleChangePowerStateToPriv() does not check the
5560 // request type, as long as the args are appropriate
5561 // for kIOPMRequestTypeChangePowerStateToPriv.
5563 request
->fArg1
= (void *) false;
5564 handleChangePowerStateToPriv( request
);
5570 IOPanic("executePMRequest: unknown request type");
5574 //*********************************************************************************
5575 // [private] servicePMReplyQueue
5576 //*********************************************************************************
5578 bool IOService::servicePMReplyQueue( IOPMRequest
* request
, IOPMRequestQueue
* queue
)
5582 assert( request
&& queue
);
5583 assert( request
->isReply() );
5585 PM_TRACE("[A %02lx] %p [%p %s] State %ld\n",
5586 request
->getType(), request
, this, getName(), fMachineState
);
5588 switch ( request
->getType() )
5590 case kIOPMRequestTypeAllowPowerChange
:
5591 case kIOPMRequestTypeCancelPowerChange
:
5592 // Check if we are expecting this response.
5593 if (responseValid((unsigned long) request
->fArg0
, (int) request
->fArg1
))
5595 if (kIOPMRequestTypeCancelPowerChange
== request
->getType())
5596 fDoNotPowerDown
= true;
5601 if ( fResponseArray
)
5603 fResponseArray
->release();
5604 fResponseArray
= NULL
;
5611 case kIOPMRequestTypeAckPowerChange
:
5612 more
= handleAcknowledgePowerChange( request
);
5615 case kIOPMRequestTypeAckSetPowerState
:
5616 if (fDriverTimer
== -1)
5618 // driver acked while setPowerState() call is in-flight.
5619 // take this ack, return value from setPowerState() is irrelevant.
5620 OUR_PMLog(kPMLogDriverAcknowledgeSet
,
5621 (UInt32
) this, fDriverTimer
);
5624 else if (fDriverTimer
> 0)
5626 // expected ack, stop the timer
5629 #if LOG_SETPOWER_TIMES
5630 uint64_t nsec
= computeTimeDeltaNS(&fDriverCallStartTime
);
5631 if (nsec
> LOG_SETPOWER_TIMES
)
5632 PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
5633 fName
, this, fCurrentPowerState
, fHeadNoteState
, NS_TO_MS(nsec
));
5635 OUR_PMLog(kPMLogDriverAcknowledgeSet
, (UInt32
) this, fDriverTimer
);
5642 OUR_PMLog(kPMLogAcknowledgeErr4
, (UInt32
) this, 0);
5646 case kIOPMRequestTypeInterestChanged
:
5647 handleInterestChanged( request
);
5652 IOPanic("servicePMReplyQueue: unknown reply type");
5655 releasePMRequest( request
);
5659 //*********************************************************************************
5660 // IOPMRequest Class
5662 // Requests from PM clients, and also used for inter-object messaging within PM.
5663 //*********************************************************************************
5665 OSDefineMetaClassAndStructors( IOPMRequest
, IOCommand
);
5667 IOPMRequest
* IOPMRequest::create( void )
5669 IOPMRequest
* me
= OSTypeAlloc(IOPMRequest
);
5670 if (me
&& !me
->init(0, kIOPMRequestTypeInvalid
))
5678 bool IOPMRequest::init( IOService
* target
, IOOptionBits type
)
5680 if (!IOCommand::init())
5687 fArg0
= fArg1
= fArg2
= 0;
5695 void IOPMRequest::reset( void )
5697 assert( fChildCount
== 0 );
5699 fType
= kIOPMRequestTypeInvalid
;
5703 fParent
->fChildCount
--;
5714 //*********************************************************************************
5715 // IOPMRequestQueue Class
5717 // Global queues. As PM-aware drivers load and unload, their IOPMWorkQueue's are
5718 // created and deallocated. IOPMRequestQueue are created once and never released.
5719 //*********************************************************************************
5721 OSDefineMetaClassAndStructors( IOPMRequestQueue
, IOEventSource
);
5723 IOPMRequestQueue
* IOPMRequestQueue::create( IOService
* inOwner
, Action inAction
)
5725 IOPMRequestQueue
* me
= OSTypeAlloc(IOPMRequestQueue
);
5726 if (me
&& !me
->init(inOwner
, inAction
))
5734 bool IOPMRequestQueue::init( IOService
* inOwner
, Action inAction
)
5736 if (!inAction
|| !IOEventSource::init(inOwner
, (IOEventSourceAction
)inAction
))
5739 queue_init(&fQueue
);
5740 fLock
= IOLockAlloc();
5741 return (fLock
!= 0);
5744 void IOPMRequestQueue::free( void )
5751 return IOEventSource::free();
5754 void IOPMRequestQueue::queuePMRequest( IOPMRequest
* request
)
5758 queue_enter(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
5759 IOLockUnlock(fLock
);
5760 if (workLoop
) signalWorkAvailable();
5764 IOPMRequestQueue::queuePMRequestChain( IOPMRequest
** requests
, IOItemCount count
)
5768 assert(requests
&& count
);
5774 queue_enter(&fQueue
, next
, IOPMRequest
*, fCommandChain
);
5776 IOLockUnlock(fLock
);
5777 if (workLoop
) signalWorkAvailable();
5780 bool IOPMRequestQueue::checkForWork( void )
5782 Action dqAction
= (Action
) action
;
5783 IOPMRequest
* request
;
5787 IOLockLock( fLock
);
5789 while (!queue_empty(&fQueue
))
5791 queue_remove_first( &fQueue
, request
, IOPMRequest
*, fCommandChain
);
5792 IOLockUnlock( fLock
);
5793 target
= request
->getTarget();
5795 more
|= (*dqAction
)( target
, request
, this );
5796 IOLockLock( fLock
);
5799 IOLockUnlock( fLock
);
5803 void IOPMRequestQueue::signalWorkAvailable( void )
5805 IOEventSource::signalWorkAvailable();
5808 //*********************************************************************************
5809 // IOPMWorkQueue Class
5811 // Every object in the power plane that has handled a PM request, will have an
5812 // instance of IOPMWorkQueue allocated for it.
5813 //*********************************************************************************
5815 OSDefineMetaClassAndStructors( IOPMWorkQueue
, IOEventSource
);
5818 IOPMWorkQueue::create( IOService
* inOwner
, Action work
, Action retire
)
5820 IOPMWorkQueue
* me
= OSTypeAlloc(IOPMWorkQueue
);
5821 if (me
&& !me
->init(inOwner
, work
, retire
))
5829 bool IOPMWorkQueue::init( IOService
* inOwner
, Action work
, Action retire
)
5831 if (!work
|| !retire
||
5832 !IOEventSource::init(inOwner
, (IOEventSourceAction
)0))
5835 queue_init(&fWorkQueue
);
5838 fRetireAction
= retire
;
5843 void IOPMWorkQueue::queuePMRequest( IOPMRequest
* request
)
5846 assert( onThread() );
5849 queue_enter(&fWorkQueue
, request
, IOPMRequest
*, fCommandChain
);
5853 bool IOPMWorkQueue::checkForWork( void )
5855 IOPMRequest
* request
;
5856 IOService
* target
= (IOService
*) owner
;
5859 while (!queue_empty(&fWorkQueue
))
5861 request
= (IOPMRequest
*) queue_first(&fWorkQueue
);
5862 assert(request
->getTarget() == target
);
5863 if (request
->hasChildRequest()) break;
5864 done
= (*fWorkAction
)( target
, request
, this );
5867 assert(gIOPMBusyCount
> 0);
5868 if (gIOPMBusyCount
) gIOPMBusyCount
--;
5869 queue_remove_first(&fWorkQueue
, request
, IOPMRequest
*, fCommandChain
);
5870 (*fRetireAction
)( target
, request
, this );
5876 OSDefineMetaClassAndStructors(IOServicePM
, OSObject
)
5878 //*********************************************************************************
5881 // Serialize IOServicePM for debugging.
5882 //*********************************************************************************
5885 setPMProperty( OSDictionary
* dict
, const char * key
, unsigned long value
)
5887 OSNumber
* num
= OSNumber::withNumber(value
, sizeof(value
) * 8);
5890 dict
->setObject(key
, num
);
5895 bool IOServicePM::serialize( OSSerialize
* s
) const
5897 OSDictionary
* dict
;
5900 dict
= OSDictionary::withCapacity(8);
5903 setPMProperty( dict
, "CurrentPowerState", CurrentPowerState
);
5904 if (DesiredPowerState
!= CurrentPowerState
)
5905 setPMProperty( dict
, "DesiredPowerState", DesiredPowerState
);
5906 if (kIOPM_Finished
!= MachineState
)
5907 setPMProperty( dict
, "MachineState", MachineState
);
5909 setPMProperty( dict
, "ChildrenPowerState", ChildrenDesire
);
5911 setPMProperty( dict
, "DeviceChangePowerState", DeviceDesire
);
5913 setPMProperty( dict
, "DriverChangePowerState", DriverDesire
);
5914 if (DeviceOverrides
)
5915 dict
->setObject( "PowerOverrideOn", kOSBooleanTrue
);
5917 ok
= dict
->serialize(s
);