2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 #include <IOKit/assert.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOKitDebug.h>
35 #include <IOKit/IOLib.h>
36 #include <IOKit/IOMessage.h>
37 #include <IOKit/IOPlatformExpert.h>
38 #include <IOKit/IOService.h>
39 #include <IOKit/IOTimerEventSource.h>
40 #include <IOKit/IOWorkLoop.h>
42 #include <IOKit/pwr_mgt/IOPMchangeNoteList.h>
43 #include <IOKit/pwr_mgt/IOPMinformee.h>
44 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
45 #include <IOKit/pwr_mgt/IOPMlog.h>
46 #include <IOKit/pwr_mgt/IOPowerConnection.h>
47 #include <IOKit/pwr_mgt/RootDomain.h>
49 #include "IOPMWorkArbiter.h"
51 // Required for notification instrumentation
52 #include "IOServicePrivate.h"
54 #define super IORegistryEntry
56 #define OUR_PMLog(t, a, b) \
57 do { pm_vars->thePlatform->PMLog(pm_vars->ourName, t, a, b); } while(0)
59 static void ack_timer_expired(thread_call_param_t
);
60 static void settle_timer_expired(thread_call_param_t
);
61 static void PM_idle_timer_expired(OSObject
*, IOTimerEventSource
*);
62 void tellAppWithResponse ( OSObject
* object
, void * context
);
63 void tellClientWithResponse ( OSObject
* object
, void * context
);
64 void tellClient ( OSObject
* object
, void * context
);
65 IOReturn
serializedAllowPowerChange ( OSObject
*, void *, void *, void *, void *);
66 IOReturn
serializedCancelPowerChange ( OSObject
*, void *, void *, void *, void *);
68 extern const IORegistryPlane
* gIOPowerPlane
;
71 // and there's 1000 nanoseconds in a microsecond:
72 #define ns_per_us 1000
75 // The current change note is processed by a state machine.
76 // Inputs are acks from interested parties, ack from the controlling driver,
77 // ack timeouts, settle timeout, and powerStateDidChange from the parent.
78 // These are the states:
80 kIOPM_OurChangeTellClientsPowerDown
= 1,
81 kIOPM_OurChangeTellPriorityClientsPowerDown
,
82 kIOPM_OurChangeNotifyInterestedDriversWillChange
,
83 kIOPM_OurChangeSetPowerState
,
84 kIOPM_OurChangeWaitForPowerSettle
,
85 kIOPM_OurChangeNotifyInterestedDriversDidChange
,
86 kIOPM_OurChangeFinish
,
87 kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate
,
88 kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
,
89 kIOPM_ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate
,
90 kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
,
91 kIOPM_ParentDownSetPowerState_Delayed
,
92 kIOPM_ParentDownWaitForPowerSettle_Delayed
,
93 kIOPM_ParentDownAcknowledgeChange_Delayed
,
94 kIOPM_ParentUpSetPowerState_Delayed
,
95 kIOPM_ParentUpSetPowerState_Immediate
,
96 kIOPM_ParentUpWaitForSettleTime_Delayed
,
97 kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed
,
98 kIOPM_ParentUpAcknowledgePowerChange_Delayed
,
102 // values of outofbandparameter
109 // used for applyToInterested
111 OSArray
* responseFlags
;
114 UInt32 maxTimeRequested
;
118 unsigned long stateNumber
;
119 IOPMPowerFlags stateFlags
;
122 // five minutes in microseconds
123 #define FIVE_MINUTES 5*60*1000000
124 #define k30seconds 30*1000000
127 There are two different kinds of power state changes. One is initiated by a subclassed device object which has either
128 decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
129 idle device and has asked it to become usable. The second kind of power state change is initiated by the power
130 domain parent. The two are handled slightly differently.
132 There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when
133 it isn't, usually there is one change note in it, but since it's possible to have more than one power state change pending
134 at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower
135 power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the
136 change note to sit in the queue until all the acks are received. During this time, the device decides it isn't idle anymore and
137 wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet,
138 so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire
139 power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
142 This is how a power change initiated by the subclass device is handled:
143 First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't
144 acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our
145 acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to
146 the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify
147 interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done.
148 If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
149 it lower the power domain state.
151 This is how a change to a lower power domain state initiated by the parent is handled:
152 First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are
153 notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume
154 that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested
155 parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify
156 our interested parties that the power state has changed, and when they have all acknowledged, we're done.
158 This is how a change to a higher power domain state initiated by the parent is handled:
159 We figure out what power state we will be in when the new domain state is reached. If it is different from our current
160 state we acknowledge the parent. When all the parent's interested parties have acknowledged, it raises power in the
161 domain and waits for power to settle. Then it notifies everyone that the new state has been reached. When we get this call,
162 we call the controlling driver, instructing it to assume the new state, and wait for power to settle. Then we notify our interested
163 parties. When they all acknowledge we are done.
165 In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples:
166 A change to a lower domain state may not affect us because we are already in a low enough state, and
167 We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
168 In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange
169 method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
170 When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
172 Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
173 four major paths through the state machine:
175 The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state.
176 The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent.
177 When the parent calls powerStateDidChange, we acknowledge the parent again, and we're done.
179 The first is fairly simple. It starts when a power domain child calls requestPowerDomainState and we decide to change power states
180 to accomodate the child, or if our power-controlling driver calls changePowerStateTo, or if some other driver which is using our
181 device calls makeUsable, or if a subclassed object calls changePowerStateToPriv. These are all power changes initiated by us, not
182 forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go
183 on to state "OurChangeSetPowerState". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
184 acknowledgePowerChange. We move on to state "OurChangeSetPowerState" when all the stragglers have acknowledged,
185 or when the ack timer expires on all those which didn't acknowledge. In "OurChangeSetPowerState" we call the power-controlling
186 driver to change the power state of the hardware. If it returns saying it has done so, we go on to state "OurChangeWaitForPowerSettle".
187 Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the
188 ack timer expires, we go on. In "OurChangeWaitForPowerSettle", we look in the power state array to see if there is any settle time required
189 when changing from our current state to the new state. If not, we go right away to "OurChangeNotifyInterestedDriversDidChange". Otherwise, we
190 set the settle timer and wait. When it expires, we move on. In "OurChangeNotifyInterestedDriversDidChange" state, we notify all our interested parties
191 via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return
192 code, we move on to "OurChangeFinish". Otherwise we set the ack timer and wait. When they have all acknowledged, or
193 when the ack timer has expired for those that didn't, we move on to "OurChangeFinish", where we remove the used
194 change note from the head of the queue and start the next one if one exists.
196 Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled
197 differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification
198 in two different ways, so each of the parent paths is really two.
200 When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
201 what state that will put our device in. Then we embark on the state machine path "IOPMParentDownSetPowerState_Immediate"
202 and "kIOPM_ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate", in which we notify interested parties of the upcoming change, instruct our driver to make
203 the change, check for settle time, and notify interested parties of the completed change. If we get to the end of this path without
204 stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
205 state right away, or due to a non-zero settling time, then we return IOPMAckImplied to the parent, and we're done with the change.
206 If we do stall in any of those states, we return IOPMWillAckLater to the parent and enter the parallel path "kIOPM_ParentDownSetPowerState_Delayed"
207 "kIOPM_ParentDownWaitForPowerSettle_Delayed", and "kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed", where we continue with the same processing, except that at the end we
208 acknowledge the parent explicitly via acknowledgePowerChange, and we're done with the change.
209 Then when the parent calls us at powerStateDidChange we acknowledging via return code, because we have already made
210 the power change. In any case, when we are done we remove the used change note from the head of the queue and start on the next one.
212 The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
213 that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
214 the parent. This case is different, though in that our device changes state in the second half, after the parent calls
215 powerStateDidChange rather than before, as in the power-lowering case.
217 When the parent calls our powerDomainWillChange method, notifying us that it will raise power in the domain, we acknowledge
218 via return code, because there's really nothing we can do until the power is actually raised in the domain.
219 When the parent calls us at powerStateDidChange, we start by notifying our interested parties. If they all acknowledge via return code,
220 we go on to" kIOPM_ParentUpSetPowerState_Immediate" to instruct the driver to raise its power level. After that, we check for any
221 necessary settling time in "IOPMParentUpWaitForSettleTime_Immediate", and we notify all interested parties that power has changed
222 in "IOPMParentUpNotifyInterestedDriversDidChange_Immediate". If none of these operations stall, we acknowledge the parent via return code, release
223 the change note, and start the next, if there is one. If one of them does stall, we enter the parallel path "kIOPM_ParentUpSetPowerState_Delayed",
224 "kIOPM_ParentUpWaitForSettleTime_Delayed", "kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed", and "kIOPM_ParentUpAcknowledgePowerChange_Delayed", which ends with
225 our explicit acknowledgement to the parent.
230 const char priv_key
[ ] = "Power Management private data";
231 const char prot_key
[ ] = "Power Management protected data";
234 void IOService::PMinit ( void )
236 if ( ! initialized
) {
238 // make space for our variables
239 pm_vars
= new IOPMprot
;
245 // add pm_vars & priv to the properties
246 setProperty(prot_key
, (OSObject
*) pm_vars
);
247 setProperty(priv_key
, (OSObject
*) priv
);
249 // then initialize them
251 pm_vars
->theNumberOfPowerStates
= 0;
252 priv
->we_are_root
= false;
253 pm_vars
->theControllingDriver
= NULL
;
254 priv
->our_lock
= IOLockAlloc();
255 priv
->flags_lock
= IOLockAlloc();
256 priv
->queue_lock
= IOLockAlloc();
257 pm_vars
->childLock
= IOLockAlloc();
258 pm_vars
->parentLock
= IOLockAlloc();
259 priv
->interestedDrivers
= new IOPMinformeeList
;
260 priv
->interestedDrivers
->initialize();
261 priv
->changeList
= new IOPMchangeNoteList
;
262 priv
->changeList
->initialize();
263 pm_vars
->aggressiveness
= 0;
264 for (unsigned int i
= 0; i
<= kMaxType
; i
++)
266 pm_vars
->current_aggressiveness_values
[i
] = 0;
267 pm_vars
->current_aggressiveness_valid
[i
] = false;
269 pm_vars
->myCurrentState
= 0;
270 priv
->imminentState
= 0;
271 priv
->ourDesiredPowerState
= 0;
272 pm_vars
->parentsCurrentPowerFlags
= 0;
273 pm_vars
->maxCapability
= 0;
274 priv
->driverDesire
= 0;
275 priv
->deviceDesire
= 0;
276 priv
->initial_change
= true;
277 priv
->need_to_become_usable
= false;
278 priv
->previousRequest
= 0;
279 priv
->device_overrides
= false;
280 priv
->machine_state
= kIOPM_Finished
;
281 priv
->timerEventSrc
= NULL
;
282 priv
->clampTimerEventSrc
= NULL
;
283 pm_vars
->PMworkloop
= NULL
;
284 priv
->activityLock
= NULL
;
285 pm_vars
->ourName
= getName();
286 pm_vars
->thePlatform
= getPlatform();
287 pm_vars
->parentsKnowState
= false;
288 assert( pm_vars
->thePlatform
!= 0 );
289 priv
->clampOn
= false;
290 pm_vars
->serialNumber
= 0;
291 pm_vars
->responseFlags
= NULL
;
292 pm_vars
->doNotPowerDown
= true;
293 pm_vars
->PMcommandGate
= NULL
;
294 priv
->ackTimer
= thread_call_allocate(
295 (thread_call_func_t
)ack_timer_expired
,
296 (thread_call_param_t
)this);
297 priv
->settleTimer
= thread_call_allocate(
298 (thread_call_func_t
)settle_timer_expired
,
299 (thread_call_param_t
)this);
306 //*********************************************************************************
309 // Free up the data created in PMinit, if it exists.
310 //*********************************************************************************
311 void IOService::PMfree ( void )
314 if ( priv
->clampTimerEventSrc
!= NULL
) {
315 getPMworkloop()->removeEventSource(priv
->clampTimerEventSrc
);
316 priv
->clampTimerEventSrc
->release();
317 priv
->clampTimerEventSrc
= NULL
;
319 if ( priv
->timerEventSrc
!= NULL
) {
320 pm_vars
->PMworkloop
->removeEventSource(priv
->timerEventSrc
);
321 priv
->timerEventSrc
->release();
322 priv
->timerEventSrc
= NULL
;
324 if ( priv
->settleTimer
) {
325 thread_call_cancel(priv
->settleTimer
);
326 thread_call_free(priv
->settleTimer
);
327 priv
->settleTimer
= NULL
;
329 if ( priv
->ackTimer
) {
330 thread_call_cancel(priv
->ackTimer
);
331 thread_call_free(priv
->ackTimer
);
332 priv
->ackTimer
= NULL
;
334 if ( priv
->our_lock
) {
335 IOLockFree(priv
->our_lock
);
336 priv
->our_lock
= NULL
;
338 if ( priv
->flags_lock
) {
339 IOLockFree(priv
->flags_lock
);
340 priv
->flags_lock
= NULL
;
342 if ( priv
->activityLock
) {
343 IOLockFree(priv
->activityLock
);
344 priv
->activityLock
= NULL
;
346 priv
->interestedDrivers
->release();
347 priv
->changeList
->release();
348 // remove instance variables
353 if ( pm_vars
->PMcommandGate
) {
354 if(pm_vars
->PMworkloop
)
355 pm_vars
->PMworkloop
->removeEventSource(pm_vars
->PMcommandGate
);
356 pm_vars
->PMcommandGate
->release();
357 pm_vars
->PMcommandGate
= NULL
;
359 if ( pm_vars
->PMworkloop
) {
360 // The work loop object returned from getPMworkLoop() is
361 // never retained, therefore it should not be released.
362 // pm_vars->PMworkloop->release();
363 pm_vars
->PMworkloop
= NULL
;
365 if ( pm_vars
->responseFlags
) {
366 pm_vars
->responseFlags
->release();
367 pm_vars
->responseFlags
= NULL
;
369 // remove instance variables
375 //*********************************************************************************
378 // Disconnect the node from its parents and children in the Power Plane.
379 //*********************************************************************************
380 void IOService::PMstop ( void )
384 IOPowerConnection
* connection
;
385 IOService
* theChild
;
386 IOService
* theParent
;
388 // remove the properties
389 removeProperty(prot_key
);
390 removeProperty(priv_key
);
393 iter
= getParentIterator(gIOPowerPlane
);
397 while ( (next
= iter
->getNextObject()) )
399 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
401 theParent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
404 theParent
->removePowerChild(connection
);
405 theParent
->release();
412 // detach IOConnections
413 detachAbove( gIOPowerPlane
);
417 // no more power state changes
418 pm_vars
->parentsKnowState
= false;
422 iter
= getChildIterator(gIOPowerPlane
);
426 while ( (next
= iter
->getNextObject()) )
428 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
430 theChild
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
433 // detach nub from child
434 connection
->detachFromChild(theChild
,gIOPowerPlane
);
437 // detach us from nub
438 detachFromChild(connection
,gIOPowerPlane
);
444 // Remove all interested drivers from the list, including the power
445 // controlling driver.
447 // Usually, the controlling driver and the policy-maker functionality
448 // are implemented by the same object, and without the deregistration,
449 // the object will be holding an extra retain on itself, and cannot
452 if ( priv
&& priv
->interestedDrivers
)
454 IOPMinformee
* informee
;
456 while (( informee
= priv
->interestedDrivers
->firstInList() ))
457 deRegisterInterestedDriver( informee
->whatObject
);
462 //*********************************************************************************
465 // A policy-maker calls its nub here when initializing, to be attached into
466 // the power management hierarchy. The default function is to call the
467 // platform expert, which knows how to do it. This method is overridden
468 // by a nub subclass which may either know how to do it, or may need
469 // to take other action.
471 // This may be the only "power management" method used in a nub,
472 // meaning it may not be initialized for power management.
473 //*********************************************************************************
474 void IOService::joinPMtree ( IOService
* driver
)
476 IOPlatformExpert
* thePlatform
;
478 thePlatform
= getPlatform();
479 assert(thePlatform
!= 0 );
480 thePlatform
->PMRegisterDevice(this,driver
);
484 //*********************************************************************************
487 // Power Managment is informing us that we are the root power domain.
488 // The only difference between us and any other power domain is that
489 // we have no parent and therefore never call it.
490 //*********************************************************************************
491 IOReturn
IOService::youAreRoot ( void )
493 priv
-> we_are_root
= true;
494 pm_vars
->parentsKnowState
= true;
495 attachToParent( getRegistryRoot(),gIOPowerPlane
);
501 //*********************************************************************************
504 // Power Management is informing us who our parent is.
505 // If we have a controlling driver, find out, given our newly-informed
506 // power domain state, what state it would be in, and then tell it
507 // to assume that state.
508 //*********************************************************************************
509 IOReturn
IOService::setPowerParent ( IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags currentState
)
513 IOPowerConnection
* connection
;
514 unsigned long tempDesire
;
516 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetParent
,stateKnown
,currentState
);
518 IOLockLock(pm_vars
->parentLock
);
520 if ( stateKnown
&& ((pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
)) )
522 // we have a path to the root
523 // find out the workloop
525 if ( pm_vars
->PMworkloop
!= NULL
)
527 if ( pm_vars
->PMcommandGate
== NULL
)
529 // and make our command gate
530 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
531 if ( pm_vars
->PMcommandGate
!= NULL
)
533 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
539 IOLockUnlock(pm_vars
->parentLock
);
541 // set our connection data
542 theParent
->setParentCurrentPowerFlags(currentState
);
543 theParent
->setParentKnowsState(stateKnown
);
545 // combine parent knowledge
546 pm_vars
->parentsKnowState
= true;
547 pm_vars
->parentsCurrentPowerFlags
= 0;
549 iter
= getParentIterator(gIOPowerPlane
);
553 while ( (next
= iter
->getNextObject()) )
555 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
557 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
558 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
564 if ( (pm_vars
->theControllingDriver
!= NULL
) &&
565 (pm_vars
->parentsKnowState
) )
567 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
568 // initially change into the state we are already in
569 tempDesire
= priv
->deviceDesire
;
570 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
571 computeDesiredState();
572 priv
->previousRequest
= 0xffffffff;
574 // put this back like before
575 priv
->deviceDesire
= tempDesire
;
582 //*********************************************************************************
585 // Power Management is informing us who our children are.
586 //*********************************************************************************
587 IOReturn
IOService::addPowerChild ( IOService
* theChild
)
589 IOPowerConnection
*connection
;
594 // we're not a power-managed IOService
595 return IOPMNotYetInitialized
;
598 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAddChild
,0,0);
600 // Put ourselves into a usable power state.
601 // We must be in an "on" power state, as our children must be able to access
602 // our hardware after joining the power plane.
603 temporaryMakeUsable();
606 connection
= new IOPowerConnection
;
609 connection
->start(this);
610 connection
->setAwaitingAck(false);
613 attachToChild( connection
,gIOPowerPlane
);
614 connection
->attachToChild( theChild
,gIOPowerPlane
);
615 connection
->release();
617 // tell it the current state of the power domain
618 if ( (pm_vars
->theControllingDriver
== NULL
) ||
619 ! (inPlane(gIOPowerPlane
)) ||
620 ! (pm_vars
->parentsKnowState
) )
622 theChild
->setPowerParent(connection
,false,0);
623 if ( inPlane(gIOPowerPlane
) )
625 for (i
= 0; i
<= kMaxType
; i
++) {
626 if ( pm_vars
->current_aggressiveness_valid
[i
] )
628 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
633 theChild
->setPowerParent(connection
,true,pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].outputPowerCharacter
);
634 for (i
= 0; i
<= kMaxType
; i
++)
636 if ( pm_vars
->current_aggressiveness_valid
[i
] )
638 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
641 // catch it up if change is in progress
642 add_child_to_active_change(connection
);
649 //******************************************************************************
652 //******************************************************************************
653 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theNub
)
655 IORegistryEntry
*theChild
;
657 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveChild
,0,0);
661 // detach nub from child
662 theChild
= theNub
->copyChildEntry(gIOPowerPlane
);
665 theNub
->detachFromChild(theChild
, gIOPowerPlane
);
668 // detach from the nub
669 detachFromChild(theNub
,gIOPowerPlane
);
671 // are we awaiting an ack from this child?
672 if ( theNub
->getAwaitingAck() )
674 // yes, pretend we got one
675 theNub
->setAwaitingAck(false);
676 if ( acquire_lock() )
678 if (priv
->head_note_pendingAcks
!= 0 )
680 // that's one fewer ack to worry about
681 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
683 if ( priv
->head_note_pendingAcks
== 0 )
685 // yes, stop the timer
687 IOUnlock(priv
->our_lock
);
688 // and now we can continue our power change
691 IOUnlock(priv
->our_lock
);
694 IOUnlock(priv
->our_lock
);
701 // if not fully initialized
702 if ( (pm_vars
->theControllingDriver
== NULL
) ||
703 !(inPlane(gIOPowerPlane
)) ||
704 !(pm_vars
->parentsKnowState
) )
710 // Perhaps the departing child was holding up idle or system sleep - we
711 // need to re-evaluate our childrens' requests.
712 // Clear and re-calculate our kIOPMChildClamp and kIOPMChildClamp2 bits.
713 rebuildChildClampBits();
715 // Change state if we can now tolerate lower power
716 computeDesiredState();
723 //*********************************************************************************
724 // registerPowerDriver
726 // A driver has called us volunteering to control power to our device.
727 // If the power state array it provides is richer than the one we already
728 // know about (supplied by an earlier volunteer), then accept the offer.
729 // Notify all interested parties of our power state, which we now know.
730 //*********************************************************************************
732 IOReturn
IOService::registerPowerDriver ( IOService
* controllingDriver
, IOPMPowerState
* powerStates
, unsigned long numberOfStates
)
735 unsigned long tempDesire
;
737 if ( (numberOfStates
> pm_vars
->theNumberOfPowerStates
)
738 && (numberOfStates
> 1) )
740 if ( priv
->changeList
->currentChange() == -1 )
742 if ( controllingDriver
!= NULL
)
744 if ( numberOfStates
<= IOPMMaxPowerStates
)
746 switch ( powerStates
[0].version
)
749 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
750 (unsigned long)numberOfStates
, (unsigned long)powerStates
[0].version
);
751 for ( i
= 0; i
< numberOfStates
; i
++ )
753 pm_vars
->thePowerStates
[i
] = powerStates
[i
];
757 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
758 (unsigned long) numberOfStates
,(unsigned long) powerStates
[0].version
);
759 for ( i
= 0; i
< numberOfStates
; i
++ )
761 pm_vars
->thePowerStates
[i
].version
= powerStates
[i
].version
;
762 pm_vars
->thePowerStates
[i
].capabilityFlags
= powerStates
[i
].capabilityFlags
;
763 pm_vars
->thePowerStates
[i
].outputPowerCharacter
= powerStates
[i
].outputPowerCharacter
;
764 pm_vars
->thePowerStates
[i
].inputPowerRequirement
= powerStates
[i
].inputPowerRequirement
;
765 pm_vars
->thePowerStates
[i
].staticPower
= powerStates
[i
].staticPower
;
766 pm_vars
->thePowerStates
[i
].unbudgetedPower
= powerStates
[i
].unbudgetedPower
;
767 pm_vars
->thePowerStates
[i
].powerToAttain
= powerStates
[i
].powerToAttain
;
768 pm_vars
->thePowerStates
[i
].timeToAttain
= powerStates
[i
].timeToAttain
;
769 pm_vars
->thePowerStates
[i
].settleUpTime
= powerStates
[i
].settleUpTime
;
770 pm_vars
->thePowerStates
[i
].timeToLower
= powerStates
[i
].timeToLower
;
771 pm_vars
->thePowerStates
[i
].settleDownTime
= powerStates
[i
].settleDownTime
;
772 pm_vars
->thePowerStates
[i
].powerDomainBudget
= powerStates
[i
].powerDomainBudget
;
776 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr1
,
777 (unsigned long)powerStates
[0].version
,0);
781 // make a mask of all the character bits we know about
782 pm_vars
->myCharacterFlags
= 0;
783 for ( i
= 0; i
< numberOfStates
; i
++ ) {
784 pm_vars
->myCharacterFlags
|= pm_vars
->thePowerStates
[i
].outputPowerCharacter
;
787 pm_vars
->theNumberOfPowerStates
= numberOfStates
;
788 pm_vars
->theControllingDriver
= controllingDriver
;
789 if ( priv
->interestedDrivers
->findItem(controllingDriver
) == NULL
)
791 // register it as interested, unless already done
792 registerInterestedDriver (controllingDriver
);
794 if ( priv
->need_to_become_usable
) {
795 priv
->need_to_become_usable
= false;
796 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
799 if ( inPlane(gIOPowerPlane
) &&
800 (pm_vars
->parentsKnowState
) ) {
801 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
802 // initially change into the state we are already in
803 tempDesire
= priv
->deviceDesire
;
804 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
805 computeDesiredState();
807 // put this back like before
808 priv
->deviceDesire
= tempDesire
;
811 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr2
,(unsigned long)numberOfStates
,0);
814 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr4
,0,0);
819 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr5
,(unsigned long)numberOfStates
,0);
824 //*********************************************************************************
825 // registerInterestedDriver
827 // Add the caller to our list of interested drivers and return our current
828 // power state. If we don't have a power-controlling driver yet, we will
829 // call this interested driver again later when we do get a driver and find
830 // out what the current power state of the device is.
831 //*********************************************************************************
833 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* theDriver
)
835 IOPMinformee
*newInformee
;
836 IOPMPowerFlags futureCapability
;
838 if (theDriver
== NULL
) {
842 // make new driver node
843 newInformee
= new IOPMinformee
;
844 newInformee
->initialize(theDriver
);
845 // add it to list of drivers
846 priv
->interestedDrivers
->addToList(newInformee
);
848 if ( (pm_vars
->theControllingDriver
== NULL
) ||
849 !(inPlane(gIOPowerPlane
)) ||
850 !(pm_vars
->parentsKnowState
) )
852 // can't tell it a state yet
853 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,IOPMNotPowerManaged
,0);
854 return IOPMNotPowerManaged
;
857 // can we notify new driver of a change in progress?
858 switch (priv
->machine_state
) {
859 case kIOPM_OurChangeSetPowerState
:
860 case kIOPM_OurChangeFinish
:
861 case kIOPM_ParentDownSetPowerState_Delayed
:
862 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
863 case kIOPM_ParentUpSetPowerState_Delayed
:
864 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
865 // yes, remember what we tell it
866 futureCapability
= priv
->head_note_capabilityFlags
;
867 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,(unsigned long)futureCapability
,1);
869 add_driver_to_active_change(newInformee
);
870 // and return the same thing
871 return futureCapability
;
874 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,
875 (unsigned long) pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
,2);
877 // no, return current capability
878 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
;
882 //*********************************************************************************
883 // deRegisterInterestedDriver
885 //*********************************************************************************
886 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* theDriver
)
888 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveDriver
,0,0);
890 // remove the departing driver
891 priv
->interestedDrivers
->removeFromList(theDriver
);
897 //*********************************************************************************
898 // acknowledgePowerChange
900 // After we notified one of the interested drivers or a power-domain child
901 // of an impending change in power, it has called to say it is now
902 // prepared for the change. If this object is the last to
903 // acknowledge this change, we take whatever action we have been waiting
905 // That may include acknowledging to our parent. In this case, we do it
906 // last of all to insure that this doesn't cause the parent to call us some-
907 // where else and alter data we are relying on here (like the very existance
908 // of a "current change note".)
909 //*********************************************************************************
911 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
913 IOPMinformee
*ackingObject
;
914 unsigned long childPower
= kIOPMUnknown
;
917 // one of our interested drivers?
918 ackingObject
= priv
->interestedDrivers
->findItem(whichObject
);
919 if ( ackingObject
== NULL
)
921 if ( ! isChild(whichObject
,gIOPowerPlane
) )
923 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr1
,0,0);
924 //kprintf("errant driver: %s\n",whichObject->getName());
928 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChildAcknowledge
,priv
->head_note_pendingAcks
,0);
931 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledge
,priv
->head_note_pendingAcks
,0);
934 if (! acquire_lock() )
939 if (priv
->head_note_pendingAcks
!= 0 )
941 // yes, make sure we're expecting acks
942 if ( ackingObject
!= NULL
)
944 // it's an interested driver
945 // make sure we're expecting this ack
946 if ( ackingObject
->timer
!= 0 )
949 ackingObject
->timer
= 0;
950 // that's one fewer to worry about
951 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
953 if ( priv
->head_note_pendingAcks
== 0 )
955 // yes, stop the timer
957 IOUnlock(priv
->our_lock
);
958 // and now we can continue
963 // this driver has already acked
964 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr2
,0,0);
965 //kprintf("errant driver: %s\n",whichObject->getName());
969 // make sure we're expecting this ack
970 if ( ((IOPowerConnection
*)whichObject
)->getAwaitingAck() )
972 // that's one fewer to worry about
973 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
974 ((IOPowerConnection
*)whichObject
)->setAwaitingAck(false);
975 theChild
= (IOService
*)whichObject
->copyChildEntry(gIOPowerPlane
);
978 childPower
= theChild
->currentPowerConsumption();
981 if ( childPower
== kIOPMUnknown
)
983 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
985 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
)
987 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
991 if ( priv
->head_note_pendingAcks
== 0 ) {
992 // yes, stop the timer
994 IOUnlock(priv
->our_lock
);
995 // and now we can continue
1002 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr3
,0,0); // not expecting anybody to ack
1003 //kprintf("errant driver: %s\n",whichObject->getName());
1005 IOUnlock(priv
->our_lock
);
1009 //*********************************************************************************
1010 // acknowledgeSetPowerState
1012 // After we instructed our controlling driver to change power states,
1013 // it has called to say it has finished doing so.
1014 // We continue to process the power state change.
1015 //*********************************************************************************
1017 IOReturn
IOService::acknowledgeSetPowerState ( void )
1019 if (!acquire_lock())
1022 IOReturn timer
= priv
->driver_timer
;
1023 if ( timer
== -1 ) {
1024 // driver is acking instead of using return code
1025 OUR_PMLog(kPMLogDriverAcknowledgeSet
, (UInt32
) this, timer
);
1026 priv
->driver_timer
= 0;
1028 else if ( timer
> 0 ) { // are we expecting this?
1029 // yes, stop the timer
1031 priv
->driver_timer
= 0;
1032 OUR_PMLog(kPMLogDriverAcknowledgeSet
, (UInt32
) this, timer
);
1033 IOUnlock(priv
->our_lock
);
1037 // not expecting this
1038 OUR_PMLog(kPMLogAcknowledgeErr4
, (UInt32
) this, 0);
1041 IOUnlock(priv
->our_lock
);
1046 //*********************************************************************************
1049 // Either the controlling driver has called acknowledgeSetPowerState
1050 // or the acknowledgement timer has expired while waiting for that.
1051 // We carry on processing the current change note.
1052 //*********************************************************************************
1054 void IOService::driver_acked ( void )
1056 getPMRootDomain()->getPMArbiter()->driverAckedOccurred(this);
1061 void IOService::driver_acked_threaded ( void )
1064 switch (priv
->machine_state
) {
1065 case kIOPM_OurChangeWaitForPowerSettle
:
1066 OurChangeWaitForPowerSettle();
1068 case kIOPM_ParentDownWaitForPowerSettle_Delayed
:
1069 ParentDownWaitForPowerSettle_Delayed();
1071 case kIOPM_ParentUpWaitForSettleTime_Delayed
:
1072 ParentUpWaitForSettleTime_Delayed();
1078 //*********************************************************************************
1079 // powerDomainWillChangeTo
1081 // Called by the power-hierarchy parent notifying of a new power state
1082 // in the power domain.
1083 // We enqueue a parent power-change to our queue of power changes.
1084 // This may or may not cause us to change power, depending on what
1085 // kind of change is occuring in the domain.
1086 //*********************************************************************************
1088 IOReturn
IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1092 IOPowerConnection
*connection
;
1093 unsigned long newStateNumber
;
1094 IOPMPowerFlags combinedPowerFlags
;
1096 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogWillChange
,(unsigned long)newPowerStateFlags
,0);
1098 if ( ! inPlane(gIOPowerPlane
) )
1101 return IOPMAckImplied
;
1104 IOLockLock(pm_vars
->parentLock
);
1106 if ( (pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
) )
1108 // we have a path to the root
1110 // so find out the workloop
1111 if ( pm_vars
->PMworkloop
!= NULL
)
1113 // and make our command gate
1114 if ( pm_vars
->PMcommandGate
== NULL
)
1116 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
1117 if ( pm_vars
->PMcommandGate
!= NULL
)
1119 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
1125 IOLockUnlock(pm_vars
->parentLock
);
1127 // combine parents' power states
1128 // to determine our maximum state within the new power domain
1129 combinedPowerFlags
= 0;
1131 iter
= getParentIterator(gIOPowerPlane
);
1135 while ( (next
= iter
->getNextObject()) )
1137 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1139 if ( connection
== whichParent
){
1140 combinedPowerFlags
|= newPowerStateFlags
;
1142 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
1149 if ( pm_vars
->theControllingDriver
== NULL
)
1151 // we can't take any more action
1152 return IOPMAckImplied
;
1154 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(combinedPowerFlags
);
1156 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainWillChange
,
1157 newStateNumber
,combinedPowerFlags
,whichParent
,newPowerStateFlags
);
1161 //*********************************************************************************
1162 // powerDomainDidChangeTo
1164 // Called by the power-hierarchy parent after the power state of the power domain
1165 // has settled at a new level.
1166 // We enqueue a parent power-change to our queue of power changes.
1167 // This may or may not cause us to change power, depending on what
1168 // kind of change is occuring in the domain.
1169 //*********************************************************************************
1171 IOReturn
IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1173 unsigned long newStateNumber
;
1175 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDidChange
,newPowerStateFlags
,0);
1177 setParentInfo(newPowerStateFlags
,whichParent
);
1179 if ( pm_vars
->theControllingDriver
== NULL
) {
1180 return IOPMAckImplied
;
1183 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
1184 // tell interested parties about it
1185 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainDidChange
,
1186 newStateNumber
,pm_vars
->parentsCurrentPowerFlags
,whichParent
,0);
1190 //*********************************************************************************
1193 // Set our connection data for one specific parent, and then combine all the parent
1195 //*********************************************************************************
1197 void IOService::setParentInfo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1201 IOPowerConnection
*connection
;
1203 // set our connection data
1204 whichParent
->setParentCurrentPowerFlags(newPowerStateFlags
);
1205 whichParent
->setParentKnowsState(true);
1207 IOLockLock(pm_vars
->parentLock
);
1209 // recompute our parent info
1210 pm_vars
->parentsCurrentPowerFlags
= 0;
1211 pm_vars
->parentsKnowState
= true;
1213 iter
= getParentIterator(gIOPowerPlane
);
1217 while ( (next
= iter
->getNextObject()) )
1219 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1221 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
1222 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
1227 IOLockUnlock(pm_vars
->parentLock
);
1230 //*********************************************************************************
1231 // rebuildChildClampBits
1233 // The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1234 // indicate that one of our children (or grandchildren or great-grandchildren or ...)
1235 // doesn't support idle or system sleep in its current state. Since we don't track the
1236 // origin of each bit, every time any child changes state we have to clear these bits
1237 // and rebuild them.
1238 //*********************************************************************************
1240 void IOService::rebuildChildClampBits(void)
1245 IOPowerConnection
*connection
;
1248 // A child's desires has changed. We need to rebuild the child-clamp bits in our
1249 // power state array. Start by clearing the bits in each power state.
1251 for ( i
= 0; i
< pm_vars
->theNumberOfPowerStates
; i
++ )
1253 pm_vars
->thePowerStates
[i
].capabilityFlags
&= ~(kIOPMChildClamp
| kIOPMChildClamp2
);
1256 // Now loop through the children. When we encounter the calling child, save
1257 // the computed state as this child's desire. And while we're at it, set the ChildClamp bits
1258 // in any of our states that some child has requested with clamp on.
1260 iter
= getChildIterator(gIOPowerPlane
);
1264 while ( (next
= iter
->getNextObject()) )
1266 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1268 if ( connection
->getPreventIdleSleepFlag() )
1269 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp
;
1270 if ( connection
->getPreventSystemSleepFlag() )
1271 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp2
;
1280 //*********************************************************************************
1281 // requestPowerDomainState
1283 // The kIOPMPreventIdleSleep and/or kIOPMPreventIdleSleep bits may be be set in the parameter.
1284 // It is not considered part of the state specification.
1285 //*********************************************************************************
1286 IOReturn
IOService::requestPowerDomainState ( IOPMPowerFlags desiredState
, IOPowerConnection
* whichChild
, unsigned long specification
)
1289 unsigned long computedState
;
1290 unsigned long theDesiredState
= desiredState
& ~(kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
1293 IOPowerConnection
*connection
;
1295 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDomain
,
1296 (unsigned long)desiredState
,(unsigned long)specification
);
1298 if ( pm_vars
->theControllingDriver
== NULL
)
1300 return IOPMNotYetInitialized
;
1303 switch (specification
) {
1304 case IOPMLowestState
:
1306 while ( i
< pm_vars
->theNumberOfPowerStates
)
1308 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) )
1314 if ( i
>= pm_vars
->theNumberOfPowerStates
)
1316 return IOPMNoSuchState
;
1320 case IOPMNextLowerState
:
1321 i
= pm_vars
->myCurrentState
- 1;
1322 while ( (int) i
>= 0 )
1324 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) )
1332 return IOPMNoSuchState
;
1336 case IOPMHighestState
:
1337 i
= pm_vars
->theNumberOfPowerStates
;
1338 while ( (int) i
>= 0 )
1341 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) )
1348 return IOPMNoSuchState
;
1352 case IOPMNextHigherState
:
1353 i
= pm_vars
->myCurrentState
+ 1;
1354 while ( i
< pm_vars
->theNumberOfPowerStates
)
1356 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) )
1362 if ( i
== pm_vars
->theNumberOfPowerStates
)
1364 return IOPMNoSuchState
;
1369 return IOPMBadSpecification
;
1374 IOLockLock(pm_vars
->childLock
);
1376 // Now loop through the children. When we encounter the calling child, save
1377 // the computed state as this child's desire.
1378 iter
= getChildIterator(gIOPowerPlane
);
1382 while ( (next
= iter
->getNextObject()) )
1384 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1386 if ( connection
== whichChild
)
1388 connection
->setDesiredDomainState(computedState
);
1389 connection
->setPreventIdleSleepFlag(desiredState
& kIOPMPreventIdleSleep
);
1390 connection
->setPreventSystemSleepFlag(desiredState
& kIOPMPreventSystemSleep
);
1391 connection
->setChildHasRequestedPower();
1398 // Since a child's power requirements may have changed, clear and rebuild
1399 // kIOPMChildClamp and kIOPMChildClamp2 (idle and system sleep clamps)
1400 rebuildChildClampBits();
1402 IOLockUnlock(pm_vars
->childLock
);
1404 // this may be different now
1405 computeDesiredState();
1407 if ( inPlane(gIOPowerPlane
) &&
1408 (pm_vars
->parentsKnowState
) ) {
1409 // change state if all children can now tolerate lower power
1413 // are we clamped on, waiting for this child?
1414 if ( priv
->clampOn
) {
1415 // yes, remove the clamp
1416 priv
->clampOn
= false;
1417 changePowerStateToPriv(0);
1424 //*********************************************************************************
1425 // temporaryPowerClampOn
1427 // A power domain wants to clamp its power on till it has children which
1428 // will thendetermine the power domain state.
1430 // We enter the highest state until addPowerChild is called.
1431 //*********************************************************************************
1433 IOReturn
IOService::temporaryPowerClampOn ( void )
1435 priv
->clampOn
= true;
1441 //*********************************************************************************
1444 // Some client of our device is asking that we become usable. Although
1445 // this has not come from a subclassed device object, treat it exactly
1446 // as if it had. In this way, subsequent requests for lower power from
1447 // a subclassed device object will pre-empt this request.
1449 // We treat this as a subclass object request to switch to the
1450 // highest power state.
1451 //*********************************************************************************
1453 IOReturn
IOService::makeUsable ( void )
1455 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogMakeUsable
,0,0);
1457 if ( pm_vars
->theControllingDriver
== NULL
)
1459 priv
->need_to_become_usable
= true;
1462 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
1463 computeDesiredState();
1464 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) )
1466 return changeState();
1471 //******************************************************************************
1472 // temporaryMakeUsable
1474 // Private function, called by IOService::addPowerChild to ensure that the
1475 // device is temporarily in a usable power state so that attached power
1476 // children may properly initialize.
1477 //******************************************************************************
1479 IOReturn
IOService::temporaryMakeUsable ( void )
1481 IOReturn ret
= kIOReturnSuccess
;
1482 unsigned long tempDesire
;
1484 pm_vars
->thePlatform
->PMLog( pm_vars
->ourName
,
1487 priv
->deviceDesire
);
1489 if ( pm_vars
->theControllingDriver
== NULL
)
1491 priv
->need_to_become_usable
= true;
1494 tempDesire
= priv
->deviceDesire
;
1495 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
1496 computeDesiredState();
1497 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) )
1499 ret
= changeState();
1501 priv
->deviceDesire
= tempDesire
;
1506 //*********************************************************************************
1507 // currentCapability
1509 //*********************************************************************************
1511 IOPMPowerFlags
IOService::currentCapability ( void )
1513 if ( pm_vars
->theControllingDriver
== NULL
)
1517 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
;
1522 //*********************************************************************************
1523 // changePowerStateTo
1525 // For some reason, our power-controlling driver has decided it needs to change
1526 // power state. We enqueue the power change so that appropriate parties
1527 // will be notified, and then we will instruct the driver to make the change.
1528 //*********************************************************************************
1530 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
1532 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateTo
,ordinal
,0);
1534 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
)
1536 return IOPMParameterError
;
1538 priv
->driverDesire
= ordinal
;
1539 computeDesiredState();
1540 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) )
1542 return changeState();
1548 //*********************************************************************************
1549 // changePowerStateToPriv
1551 // For some reason, a subclassed device object has decided it needs to change
1552 // power state. We enqueue the power change so that appropriate parties
1553 // will be notified, and then we will instruct the driver to make the change.
1554 //*********************************************************************************
1556 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
1558 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateToPriv
,ordinal
,0);
1560 if ( pm_vars
->theControllingDriver
== NULL
)
1562 return IOPMNotYetInitialized
;
1564 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
)
1566 return IOPMParameterError
;
1568 priv
->deviceDesire
= ordinal
;
1569 computeDesiredState();
1570 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) )
1572 return changeState();
1579 //*********************************************************************************
1580 // computeDesiredState
1582 //*********************************************************************************
1584 void IOService::computeDesiredState ( void )
1588 IOPowerConnection
*connection
;
1589 unsigned long newDesiredState
= 0;
1591 // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire.
1592 if ( ! priv
->device_overrides
)
1594 iter
= getChildIterator(gIOPowerPlane
);
1598 while ( (next
= iter
->getNextObject()) )
1600 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1602 if ( connection
->getDesiredDomainState() > newDesiredState
)
1604 newDesiredState
= connection
->getDesiredDomainState();
1611 if ( priv
->driverDesire
> newDesiredState
)
1613 newDesiredState
= priv
->driverDesire
;
1617 if ( priv
->deviceDesire
> newDesiredState
)
1619 newDesiredState
= priv
->deviceDesire
;
1622 priv
->ourDesiredPowerState
= newDesiredState
;
1626 //*********************************************************************************
1629 // A subclass object, our controlling driver, or a power domain child
1630 // has asked for a different power state. Here we compute what new
1631 // state we should enter and enqueue the change (or start it).
1632 //*********************************************************************************
1634 IOReturn
IOService::changeState ( void )
1636 // if not fully initialized
1637 if ( (pm_vars
->theControllingDriver
== NULL
) ||
1638 !(inPlane(gIOPowerPlane
)) ||
1639 !(pm_vars
->parentsKnowState
) )
1641 // we can do no more
1645 return enqueuePowerChange(IOPMWeInitiated
,priv
->ourDesiredPowerState
,0,0,0);
1649 //*********************************************************************************
1650 // currentPowerConsumption
1652 //*********************************************************************************
1654 unsigned long IOService::currentPowerConsumption ( void )
1656 if ( pm_vars
->theControllingDriver
== NULL
)
1658 return kIOPMUnknown
;
1660 if ( pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
& kIOPMStaticPowerValid
)
1662 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].staticPower
;
1664 return kIOPMUnknown
;
1667 //*********************************************************************************
1670 // The activity tickle with parameter kIOPMSubclassPolicyis not handled
1671 // here and should have been intercepted by the subclass.
1672 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
1673 // flag to be set, and the device state checked. If the device has been
1674 // powered down, it is powered up again.
1675 //*********************************************************************************
1677 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
)
1679 IOPMrootDomain
*pmRootDomain
;
1680 AbsoluteTime uptime
;
1682 if ( type
== kIOPMSuperclassPolicy1
)
1684 if ( pm_vars
->theControllingDriver
== NULL
)
1689 if( priv
->activityLock
== NULL
)
1691 priv
->activityLock
= IOLockAlloc();
1694 IOTakeLock(priv
->activityLock
);
1695 priv
->device_active
= true;
1697 clock_get_uptime(&uptime
);
1698 priv
->device_active_timestamp
= uptime
;
1700 if ( pm_vars
->myCurrentState
>= stateNumber
)
1702 IOUnlock(priv
->activityLock
);
1705 IOUnlock(priv
->activityLock
);
1707 // Transfer execution to the PM workloop
1708 if( (pmRootDomain
= getPMRootDomain()) )
1709 pmRootDomain
->unIdleDevice(this, stateNumber
);
1716 //*********************************************************************************
1719 // A child is calling to get a pointer to the Power Management workloop.
1720 // We got it or get it from one of our parents.
1721 //*********************************************************************************
1723 IOWorkLoop
* IOService::getPMworkloop ( void )
1728 if ( ! inPlane(gIOPowerPlane
) )
1732 // we have no workloop yet
1733 if ( pm_vars
->PMworkloop
== NULL
)
1735 nub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
1738 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
1740 // ask one of our parents for the workloop
1743 pm_vars
->PMworkloop
= parent
->getPMworkloop();
1748 return pm_vars
->PMworkloop
;
1752 //*********************************************************************************
1753 // setIdleTimerPeriod
1755 // A subclass policy-maker is going to use our standard idleness
1756 // detection service. Make a command queue and an idle timer and
1757 // connect them to the power management workloop. Finally,
1759 //*********************************************************************************
1761 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
1763 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMsetIdleTimerPeriod
,period
, 0);
1765 priv
->idle_timer_period
= period
;
1769 if ( getPMworkloop() == NULL
)
1771 return kIOReturnError
;
1774 // make the timer event
1775 if ( priv
->timerEventSrc
== NULL
)
1777 priv
->timerEventSrc
= IOTimerEventSource::timerEventSource(this,
1778 PM_idle_timer_expired
);
1779 if ((!priv
->timerEventSrc
) ||
1780 (pm_vars
->PMworkloop
->addEventSource(priv
->timerEventSrc
) != kIOReturnSuccess
) )
1782 return kIOReturnError
;
1786 if ( priv
->activityLock
== NULL
)
1788 priv
->activityLock
= IOLockAlloc();
1791 start_PM_idle_timer();
1796 //******************************************************************************
1799 // Returns how many "seconds from now" the device should idle into its
1800 // next lowest power state.
1801 //******************************************************************************
1802 SInt32
IOService::nextIdleTimeout(
1803 AbsoluteTime currentTime
,
1804 AbsoluteTime lastActivity
,
1805 unsigned int powerState
)
1812 // Calculate time difference using funky macro from clock.h.
1813 delta
= currentTime
;
1814 SUB_ABSOLUTETIME(&delta
, &lastActivity
);
1816 // Figure it in seconds.
1817 absolutetime_to_nanoseconds(delta
, &delta_ns
);
1818 delta_secs
= (SInt32
)(delta_ns
/ NSEC_PER_SEC
);
1820 // Be paranoid about delta somehow exceeding timer period.
1821 if (delta_secs
< (int) priv
->idle_timer_period
)
1822 delay_secs
= (int) priv
->idle_timer_period
- delta_secs
;
1824 delay_secs
= (int) priv
->idle_timer_period
;
1826 return (SInt32
)delay_secs
;
1829 //******************************************************************************
1830 // start_PM_idle_timer
1832 // The parameter is a pointer to us. Use it to call our timeout method.
1833 //******************************************************************************
1834 void IOService::start_PM_idle_timer ( void )
1836 static const int maxTimeout
= 100000;
1837 static const int minTimeout
= 1;
1838 AbsoluteTime uptime
;
1841 IOLockLock(priv
->activityLock
);
1843 clock_get_uptime(&uptime
);
1845 // Subclasses may modify idle sleep algorithm
1846 idle_in
= nextIdleTimeout(uptime
,
1847 priv
->device_active_timestamp
,
1848 pm_vars
->myCurrentState
);
1850 // Check for out-of range responses
1851 if(idle_in
> maxTimeout
)
1853 // use standard implementation
1854 idle_in
= IOService::nextIdleTimeout(uptime
,
1855 priv
->device_active_timestamp
,
1856 pm_vars
->myCurrentState
);
1857 } else if(idle_in
< minTimeout
) {
1862 priv
->timerEventSrc
->setTimeout(idle_in
, NSEC_PER_SEC
);
1864 IOLockUnlock(priv
->activityLock
);
1869 //*********************************************************************************
1870 // PM_idle_timer_expired
1872 // The parameter is a pointer to us. Use it to call our timeout method.
1873 //*********************************************************************************
1875 void PM_idle_timer_expired(OSObject
* ourSelves
, IOTimerEventSource
*)
1877 ((IOService
*)ourSelves
)->PM_idle_timer_expiration();
1881 //*********************************************************************************
1882 // PM_idle_timer_expiration
1884 // The idle timer has expired. If there has been activity since the last
1885 // expiration, just restart the timer and return. If there has not been
1886 // activity, switch to the next lower power state and restart the timer.
1887 //*********************************************************************************
1889 void IOService::PM_idle_timer_expiration ( void )
1891 if ( ! initialized
)
1897 if ( priv
->idle_timer_period
> 0 )
1899 IOTakeLock(priv
->activityLock
);
1900 if ( priv
->device_active
)
1902 priv
->device_active
= false;
1903 IOUnlock(priv
->activityLock
);
1904 start_PM_idle_timer();
1907 if ( pm_vars
->myCurrentState
> 0 )
1910 unsigned long newState
= pm_vars
->myCurrentState
- 1;
1912 IOUnlock(priv
->activityLock
);
1913 changePowerStateToPriv(newState
);
1914 if ( newState
>= priv
->ourDesiredPowerState
)
1915 start_PM_idle_timer();
1918 IOUnlock(priv
->activityLock
);
1919 start_PM_idle_timer();
1924 // **********************************************************************************
1927 // We are un-idling a device due to its activity tickle. This routine runs on the
1928 // PM workloop, and is initiated by IOService::activityTickle.
1929 // We process all activityTickle state requests on the list.
1930 // **********************************************************************************
1931 void IOService::command_received ( void *statePtr
, void *, void * , void * )
1933 unsigned long stateNumber
;
1935 stateNumber
= (unsigned long)statePtr
;
1937 // If not initialized, we're unloading
1938 if ( ! initialized
) return;
1940 if ( (pm_vars
->myCurrentState
< stateNumber
) &&
1941 (priv
->imminentState
< stateNumber
) )
1943 changePowerStateToPriv(stateNumber
);
1945 // After we raise our state, re-schedule the idle timer.
1946 if(priv
->timerEventSrc
)
1947 start_PM_idle_timer();
1952 //*********************************************************************************
1953 // setAggressiveness
1955 // Pass on the input parameters to all power domain children. All those which are
1956 // power domains will pass it on to their children, etc.
1957 //*********************************************************************************
1959 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
1963 IOPowerConnection
*connection
;
1966 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetAggressiveness
,type
, newLevel
);
1968 if ( type
<= kMaxType
)
1970 pm_vars
->current_aggressiveness_values
[type
] = newLevel
;
1971 pm_vars
->current_aggressiveness_valid
[type
] = true;
1974 iter
= getChildIterator(gIOPowerPlane
);
1978 while ( (next
= iter
->getNextObject()) )
1980 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1982 child
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
1985 child
->setAggressiveness(type
, newLevel
);
1996 //*********************************************************************************
1997 // getAggressiveness
1999 // Called by the user client.
2000 //*********************************************************************************
2002 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
2004 if ( type
> kMaxType
)
2005 return kIOReturnBadArgument
;
2007 if ( !pm_vars
->current_aggressiveness_valid
[type
] )
2008 return kIOReturnInvalid
;
2010 *currentLevel
= pm_vars
->current_aggressiveness_values
[type
];
2012 return kIOReturnSuccess
;
2015 //*********************************************************************************
2018 // Pass this to all power domain children. All those which are
2019 // power domains will pass it on to their children, etc.
2020 //*********************************************************************************
2022 IOReturn
IOService::systemWake ( void )
2026 IOPowerConnection
*connection
;
2027 IOService
*theChild
;
2029 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSystemWake
,0, 0);
2031 iter
= getChildIterator(gIOPowerPlane
);
2035 while ( (next
= iter
->getNextObject()) )
2037 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
2039 theChild
= (IOService
*)connection
->copyChildEntry(gIOPowerPlane
);
2042 theChild
->systemWake();
2043 theChild
->release();
2050 if ( pm_vars
->theControllingDriver
!= NULL
)
2052 if ( pm_vars
->theControllingDriver
->didYouWakeSystem() )
2062 //*********************************************************************************
2063 // temperatureCriticalForZone
2065 //*********************************************************************************
2067 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
2069 IOService
*theParent
;
2072 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCriticalTemp
,0,0);
2074 if ( inPlane(gIOPowerPlane
) && !(priv
->we_are_root
) )
2076 theNub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
2079 theParent
= (IOService
*)theNub
->copyParentEntry(gIOPowerPlane
);
2083 theParent
->temperatureCriticalForZone(whichZone
);
2084 theParent
->release();
2092 //*********************************************************************************
2093 // powerOverrideOnPriv
2095 //*********************************************************************************
2098 IOReturn
IOService::powerOverrideOnPriv ( void )
2100 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOn
,0,0);
2102 // turn on the override
2103 priv
->device_overrides
= true;
2104 computeDesiredState();
2106 // change state if that changed something
2107 return changeState();
2111 //*********************************************************************************
2112 // powerOverrideOffPriv
2114 //*********************************************************************************
2115 IOReturn
IOService::powerOverrideOffPriv ( void )
2117 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOff
,0,0);
2119 // turn off the override
2120 priv
->device_overrides
= false;
2121 computeDesiredState();
2124 return makeUsable();
2126 // change state if that changed something
2127 return changeState();
2132 //*********************************************************************************
2133 // enqueuePowerChange
2135 // Allocate a new state change notification, initialize it with fields from the
2136 // caller, and add it to the tail of the list of pending power changes.
2138 // If it is early enough in the list, and almost all the time it is the only one in
2139 // the list, start the power change.
2141 // In rare instances, this change will preempt the previous change in the list.
2142 // If the previous change is un-actioned in any way (because we are still
2143 // processing an even earlier power change), and if both the previous change
2144 // in the list and this change are initiated by us (not the parent), then we
2145 // needn't perform the previous change, so we collapse the list a little.
2146 //*********************************************************************************
2148 IOReturn
IOService::enqueuePowerChange (
2149 unsigned long flags
,
2150 unsigned long whatStateOrdinal
,
2151 unsigned long domainState
,
2152 IOPowerConnection
* whichParent
,
2153 unsigned long singleParentState
)
2158 // Create and initialize the new change note
2160 IOLockLock(priv
->queue_lock
);
2161 newNote
= priv
->changeList
->createChangeNote();
2162 if ( newNote
== -1 ) {
2163 // uh-oh, our list is full
2164 IOLockUnlock(priv
->queue_lock
);
2165 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogEnqueueErr
,0,0);
2166 return IOPMAckImplied
;
2169 priv
->changeList
->changeNote
[newNote
].newStateNumber
= whatStateOrdinal
;
2170 priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
= pm_vars
->thePowerStates
[whatStateOrdinal
].outputPowerCharacter
;
2171 priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
= pm_vars
->thePowerStates
[whatStateOrdinal
].inputPowerRequirement
;
2172 priv
->changeList
->changeNote
[newNote
].capabilityFlags
= pm_vars
->thePowerStates
[whatStateOrdinal
].capabilityFlags
;
2173 priv
->changeList
->changeNote
[newNote
].flags
= flags
;
2174 priv
->changeList
->changeNote
[newNote
].parent
= NULL
;
2175 if (flags
& IOPMParentInitiated
)
2177 priv
->changeList
->changeNote
[newNote
].domainState
= domainState
;
2178 priv
->changeList
->changeNote
[newNote
].parent
= whichParent
;
2179 whichParent
->retain();
2180 priv
->changeList
->changeNote
[newNote
].singleParentState
= singleParentState
;
2183 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
2185 if ( previousNote
== -1 )
2188 // Queue is empty, we can start this change.
2190 if (flags
& IOPMWeInitiated
)
2192 IOLockUnlock(priv
->queue_lock
);
2193 start_our_change(newNote
);
2196 IOLockUnlock(priv
->queue_lock
);
2197 return start_parent_change(newNote
);
2201 // The queue is not empty. Try to collapse this new change and the previous one in queue into one change.
2202 // This is possible only if both changes are initiated by us, and neither has been started yet.
2203 // Do this more than once if possible.
2205 // (A change is started iff it is at the head of the queue)
2207 while ( (previousNote
!= priv
->head_note
) && (previousNote
!= -1) &&
2208 (priv
->changeList
->changeNote
[newNote
].flags
& priv
->changeList
->changeNote
[previousNote
].flags
& IOPMWeInitiated
) )
2210 priv
->changeList
->changeNote
[previousNote
].outputPowerCharacter
= priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
;
2211 priv
->changeList
->changeNote
[previousNote
].inputPowerRequirement
= priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
;
2212 priv
->changeList
->changeNote
[previousNote
].capabilityFlags
=priv
-> changeList
->changeNote
[newNote
].capabilityFlags
;
2213 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCollapseQueue
,priv
->changeList
->changeNote
[newNote
].newStateNumber
,
2214 priv
->changeList
->changeNote
[previousNote
].newStateNumber
);
2215 priv
->changeList
->changeNote
[previousNote
].newStateNumber
= priv
->changeList
->changeNote
[newNote
].newStateNumber
;
2216 priv
->changeList
->releaseTailChangeNote();
2217 newNote
= previousNote
;
2218 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
2220 IOLockUnlock(priv
->queue_lock
);
2221 // in any case, we can't start yet
2222 return IOPMWillAckLater
;
2225 //*********************************************************************************
2228 // Notify all interested parties either that a change is impending or that the
2229 // previously-notified change is done and power has settled.
2230 // The parameter identifies whether this is the
2231 // pre-change notification or the post-change notification.
2233 //*********************************************************************************
2235 IOReturn
IOService::notifyAll ( bool is_prechange
)
2237 IOPMinformee
* nextObject
;
2240 IOPowerConnection
* connection
;
2242 // To prevent acknowledgePowerChange from finishing the change note and
2243 // removing it from the queue if
2244 // some driver calls it, we inflate the number of pending acks so it
2245 // cannot become zero. We'll fix it later.
2247 if(!acquire_lock()) return IOPMAckImplied
;
2249 OSAddAtomic(1, (SInt32
*)&priv
->head_note_pendingAcks
);
2251 // OK, we will go through the lists of interested drivers and
2252 // power domain children and notify each one of this change.
2254 nextObject
= priv
->interestedDrivers
->firstInList();
2255 while ( nextObject
!= NULL
) {
2257 OSAddAtomic(1, (SInt32
*)&priv
->head_note_pendingAcks
);
2259 IOUnlock(priv
->our_lock
);
2261 inform(nextObject
, is_prechange
);
2268 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
2271 // did they all ack?
2272 if ( priv
->head_note_pendingAcks
> 1 ) {
2274 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2278 IOUnlock(priv
->our_lock
);
2281 iter
= getChildIterator(gIOPowerPlane
);
2282 // summing their power consumption
2283 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= 0;
2285 if ( iter
&& acquire_lock())
2287 while ( (next
= iter
->getNextObject()) )
2289 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
2291 OSAddAtomic(1, (SInt32
*)&priv
->head_note_pendingAcks
);
2293 IOUnlock(priv
->our_lock
);
2295 notifyChild(connection
, is_prechange
);
2304 IOUnlock(priv
->our_lock
);
2307 if (! acquire_lock() ) {
2310 // now make this real
2311 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
2314 if (priv
->head_note_pendingAcks
== 0 ) {
2316 IOUnlock(priv
->our_lock
);
2317 // return ack to parent
2318 return IOPMAckImplied
;
2322 IOUnlock(priv
->our_lock
);
2324 exit
: // unable to acquire_lock exit case
2326 return IOPMWillAckLater
;
2330 //*********************************************************************************
2333 // Notify a power domain child of an upcoming power change.
2335 // If the object acknowledges the current change, we return TRUE.
2336 //*********************************************************************************
2338 bool IOService::notifyChild ( IOPowerConnection
* theNub
, bool is_prechange
)
2340 IOReturn k
= IOPMAckImplied
;
2341 unsigned long childPower
;
2342 IOService
*theChild
;
2344 theChild
= (IOService
*)(theNub
->copyChildEntry(gIOPowerPlane
));
2347 // The child has been detached since we grabbed the child iterator.
2348 // Decrement pending_acks, already incremented in notifyAll,
2349 // to account for this unexpected departure.
2351 if( acquire_lock() )
2353 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
2354 IOUnlock(priv
->our_lock
);
2359 // Unless the child handles the notification immediately and returns
2360 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
2361 theNub
->setAwaitingAck(true);
2365 k
= theChild
->powerDomainWillChangeTo(priv
->head_note_outputFlags
,theNub
);
2367 k
= theChild
->powerDomainDidChangeTo(priv
->head_note_outputFlags
,theNub
);
2370 // did the return code ack?
2371 if ( k
== IOPMAckImplied
)
2374 if( acquire_lock() )
2376 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
2377 IOUnlock(priv
->our_lock
);
2380 theNub
->setAwaitingAck(false);
2381 childPower
= theChild
->currentPowerConsumption();
2382 if ( childPower
== kIOPMUnknown
)
2384 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
2386 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
)
2388 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
2391 theChild
->release();
2394 theChild
->release();
2399 //*********************************************************************************
2402 // Notify an interested driver of an upcoming power change.
2404 // If the object acknowledges the current change, we return TRUE.
2405 //*********************************************************************************
2407 bool IOService::inform ( IOPMinformee
* nextObject
, bool is_prechange
)
2409 IOReturn k
= IOPMAckImplied
;
2412 nextObject
->timer
= -1;
2416 pm_vars
->thePlatform
->PMLog (pm_vars
->ourName
,PMlogInformDriverPreChange
,
2417 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
2418 k
= nextObject
->whatObject
->powerStateWillChangeTo( priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
2420 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInformDriverPostChange
,
2421 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
2422 k
= nextObject
->whatObject
->powerStateDidChangeTo(priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
2425 // did it ack behind our back?
2426 if ( nextObject
->timer
== 0 )
2432 if ( (k
==IOPMAckImplied
) // no, did the return code ack?
2433 || (k
< 0) ) // somebody goofed
2436 nextObject
->timer
= 0;
2438 if( acquire_lock() )
2440 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
2441 IOUnlock(priv
->our_lock
);
2447 nextObject
->timer
= (k
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
2453 //*********************************************************************************
2454 // OurChangeTellClientsPowerDown
2456 // All registered applications and kernel clients have positively acknowledged our
2457 // intention of lowering power. Here we notify them all that we will definitely
2458 // lower the power. If we don't have to wait for any of them to acknowledge, we
2459 // carry on by notifying interested drivers. Otherwise, we do wait.
2460 //*********************************************************************************
2462 void IOService::OurChangeTellClientsPowerDown ( void )
2465 priv
->machine_state
= kIOPM_OurChangeTellPriorityClientsPowerDown
;
2467 // are we waiting for responses?
2468 if ( tellChangeDown1(priv
->head_note_state
) )
2470 // no, notify priority clients
2471 OurChangeTellPriorityClientsPowerDown();
2473 // If we are waiting for responses, execution will resume via
2474 // allowCancelCommon() or ack timeout
2478 //*********************************************************************************
2479 // OurChangeTellPriorityClientsPowerDown
2481 // All registered applications and kernel clients have positively acknowledged our
2482 // intention of lowering power. Here we notify "priority" clients that we are
2483 // lowering power. If we don't have to wait for any of them to acknowledge, we
2484 // carry on by notifying interested drivers. Otherwise, we do wait.
2485 //*********************************************************************************
2487 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
2490 priv
->machine_state
= kIOPM_OurChangeNotifyInterestedDriversWillChange
;
2491 // are we waiting for responses?
2492 if ( tellChangeDown2(priv
->head_note_state
) )
2494 // no, notify interested drivers
2495 return OurChangeNotifyInterestedDriversWillChange();
2497 // If we are waiting for responses, execution will resume via
2498 // allowCancelCommon() or ack timeout
2502 //*********************************************************************************
2503 // OurChangeNotifyInterestedDriversWillChange
2505 // All registered applications and kernel clients have acknowledged our notification
2506 // that we are lowering power. Here we notify interested drivers. If we don't have
2507 // to wait for any of them to acknowledge, we instruct our power driver to make the change.
2508 // Otherwise, we do wait.
2509 //*********************************************************************************
2511 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
2513 // no, in case they don't all ack
2514 priv
->machine_state
= kIOPM_OurChangeSetPowerState
;
2515 if ( notifyAll(true) == IOPMAckImplied
)
2517 // not waiting for responses
2518 OurChangeSetPowerState();
2520 // If we are waiting for responses, execution will resume via
2521 // all_acked() or ack timeout
2525 //*********************************************************************************
2526 // OurChangeSetPowerState
2528 // All interested drivers have acknowledged our pre-change notification of a power
2529 // change we initiated. Here we instruct our controlling driver to make
2530 // the change to the hardware. If it does so, we continue processing
2531 // (waiting for settle and notifying interested parties post-change.)
2532 // If it doesn't, we have to wait for it to acknowledge and then continue.
2533 //*********************************************************************************
2535 void IOService::OurChangeSetPowerState ( void )
2537 priv
->machine_state
= kIOPM_OurChangeWaitForPowerSettle
;
2539 IOLockLock(priv
->our_lock
);
2541 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2543 // it's done, carry on
2544 IOLockUnlock(priv
->our_lock
);
2545 OurChangeWaitForPowerSettle();
2547 // it's not, wait for it
2548 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2550 IOLockUnlock(priv
->our_lock
);
2551 // execution will resume via ack_timer_ticked()
2556 //*********************************************************************************
2557 // OurChangeWaitForPowerSettle
2559 // Our controlling driver has changed power state on the hardware
2560 // during a power change we initiated. Here we see if we need to wait
2561 // for power to settle before continuing. If not, we continue processing
2562 // (notifying interested parties post-change). If so, we wait and
2564 //*********************************************************************************
2566 void IOService::OurChangeWaitForPowerSettle ( void )
2568 priv
->settle_time
= compute_settle_time();
2569 if ( priv
->settle_time
== 0 )
2571 OurChangeNotifyInterestedDriversDidChange();
2573 priv
->machine_state
= kIOPM_OurChangeNotifyInterestedDriversDidChange
;
2574 startSettleTimer(priv
->settle_time
);
2579 //*********************************************************************************
2580 // OurChangeNotifyInterestedDriversDidChange
2582 // Power has settled on a power change we initiated. Here we notify
2583 // all our interested parties post-change. If they all acknowledge, we're
2584 // done with this change note, and we can start on the next one.
2585 // Otherwise we have to wait for acknowledgements and finish up later.
2586 //*********************************************************************************
2588 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
2590 // in case they don't all ack
2591 priv
->machine_state
= kIOPM_OurChangeFinish
;
2592 if ( notifyAll(false) == IOPMAckImplied
)
2594 // not waiting for responses
2597 // If we are waiting for responses, execution will resume via
2598 // all_acked() or ack timeout
2602 //*********************************************************************************
2605 // Power has settled on a power change we initiated, and
2606 // all our interested parties have acknowledged. We're
2607 // done with this change note, and we can start on the next one.
2608 //*********************************************************************************
2610 void IOService::OurChangeFinish ( void )
2616 //*********************************************************************************
2617 // ParentDownTellPriorityClientsPowerDown_Immediate
2619 // All applications and kernel clients have been notified of a power lowering
2620 // initiated by the parent and we didn't have to wait for any responses. Here
2621 // we notify any priority clients. If they all ack, we continue with the power change.
2622 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2623 //*********************************************************************************
2625 IOReturn
IOService::ParentDownTellPriorityClientsPowerDown_Immediate ( void )
2627 // in case they don't all ack
2628 priv
->machine_state
= kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
;
2629 // are we waiting for responses?
2630 if ( tellChangeDown2(priv
->head_note_state
) )
2632 // no, notify interested drivers
2633 return ParentDownNotifyInterestedDriversWillChange_Immediate();
2635 // If we are waiting for responses, execution will resume via
2636 // allowCancelCommon() or ack timeout
2637 return IOPMWillAckLater
;
2641 //*********************************************************************************
2642 // ParentDownTellPriorityClientsPowerDown_Immediate2
2644 // All priority kernel clients have been notified of a power lowering
2645 // initiated by the parent and we didn't have to wait for any responses. Here
2646 // we notify any interested drivers and power domain children. If they all ack,
2647 // we continue with the power change.
2648 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2649 //*********************************************************************************
2651 IOReturn
IOService::ParentDownNotifyInterestedDriversWillChange_Immediate ( void )
2653 // in case they don't all ack
2654 priv
->machine_state
= kIOPM_ParentDownSetPowerState_Delayed
;
2655 if ( notifyAll(true) == IOPMAckImplied
)
2658 return ParentDownSetPowerState_Immediate();
2660 // If we are waiting for responses, execution will resume via
2661 // all_acked() or ack timeout
2662 return IOPMWillAckLater
;
2666 //*********************************************************************************
2667 // ParentDownTellPriorityClientsPowerDown_Immediate4
2669 // All applications and kernel clients have been notified of a power lowering
2670 // initiated by the parent and we had to wait for responses. Here
2671 // we notify any priority clients. If they all ack, we continue with the power change.
2672 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2673 //*********************************************************************************
2675 void IOService::ParentDownTellPriorityClientsPowerDown_Delayed ( void )
2677 // in case they don't all ack
2678 priv
->machine_state
= kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
;
2680 // are we waiting for responses?
2681 if ( tellChangeDown2(priv
->head_note_state
) )
2683 // no, notify interested drivers
2684 ParentDownNotifyInterestedDriversWillChange_Delayed();
2686 // If we are waiting for responses, execution will resume via
2687 // allowCancelCommon() or ack timeout
2691 //*********************************************************************************
2692 // ParentDownTellPriorityClientsPowerDown_Immediate5
2694 // All applications and kernel clients have been notified of a power lowering
2695 // initiated by the parent and we had to wait for their responses. Here we notify
2696 // any interested drivers and power domain children. If they all ack, we continue
2697 // with the power change.
2698 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2699 //*********************************************************************************
2701 void IOService::ParentDownNotifyInterestedDriversWillChange_Delayed ( void )
2703 // in case they don't all ack
2704 priv
->machine_state
= kIOPM_ParentDownSetPowerState_Delayed
;
2705 if ( notifyAll(true) == IOPMAckImplied
)
2708 ParentDownSetPowerState_Delayed();
2710 // If we are waiting for responses, execution will resume via
2711 // all_acked() or ack timeout
2715 //*********************************************************************************
2716 // ParentDownSetPowerState_Immediate
2718 // All parties have acknowledged our pre-change notification of a power
2719 // lowering initiated by the parent. Here we instruct our controlling driver
2720 // to put the hardware in the state it needs to be in when the domain is
2721 // lowered. If it does so, we continue processing
2722 // (waiting for settle and acknowledging the parent.)
2723 // If it doesn't, we have to wait for it to acknowledge and then continue.
2724 //*********************************************************************************
2726 IOReturn
IOService::ParentDownSetPowerState_Immediate ( void )
2728 priv
->machine_state
= kIOPM_ParentDownWaitForPowerSettle_Delayed
;
2730 IOLockLock(priv
->our_lock
);
2732 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2734 // it's done, carry on
2735 IOLockUnlock(priv
->our_lock
);
2736 return ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate();
2738 // it's not, wait for it
2739 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2741 IOLockUnlock(priv
->our_lock
);
2742 return IOPMWillAckLater
;
2746 //*********************************************************************************
2747 // ParentDownSetPowerState_Delayed
2749 // We had to wait for it, but all parties have acknowledged our pre-change
2750 // notification of a power lowering initiated by the parent.
2751 // Here we instruct our controlling driver
2752 // to put the hardware in the state it needs to be in when the domain is
2753 // lowered. If it does so, we continue processing
2754 // (waiting for settle and acknowledging the parent.)
2755 // If it doesn't, we have to wait for it to acknowledge and then continue.
2756 //*********************************************************************************
2758 void IOService::ParentDownSetPowerState_Delayed ( void )
2760 priv
-> machine_state
= kIOPM_ParentDownWaitForPowerSettle_Delayed
;
2762 IOLockLock(priv
->our_lock
);
2764 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2766 // it's done, carry on
2767 IOLockUnlock(priv
->our_lock
);
2768 ParentDownWaitForPowerSettle_Delayed();
2770 // it's not, wait for it
2771 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2773 IOLockUnlock(priv
->our_lock
);
2778 //*********************************************************************************
2779 // ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate
2781 // Our controlling driver has changed power state on the hardware
2782 // during a power change initiated by our parent. Here we see if we need
2783 // to wait for power to settle before continuing. If not, we continue
2784 // processing (acknowledging our preparedness to the parent).
2785 // If so, we wait and continue later.
2786 //*********************************************************************************
2788 IOReturn
IOService::ParentDownWaitForPowerSettleAndNotifyDidChange_Immediate ( void )
2792 priv
->settle_time
= compute_settle_time();
2793 if ( priv
->settle_time
== 0 )
2795 // store current state in case they don't all ack
2796 priv
->machine_state
= kIOPM_ParentDownAcknowledgeChange_Delayed
;
2797 if ( notifyAll(false) == IOPMAckImplied
)
2799 // not waiting for responses
2800 nub
= priv
->head_note_parent
;
2804 return IOPMAckImplied
;
2806 // If we are waiting for responses, execution will resume via
2807 // all_acked() or ack timeout
2808 return IOPMWillAckLater
;
2810 // let settle time elapse, then notify interest drivers of our power state change in ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
2811 priv
->machine_state
= kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
;
2812 startSettleTimer(priv
->settle_time
);
2813 return IOPMWillAckLater
;
2818 //*********************************************************************************
2819 // ParentDownWaitForPowerSettle_Delayed
2821 // Our controlling driver has changed power state on the hardware
2822 // during a power change initiated by our parent. We have had to wait
2823 // for acknowledgement from interested parties, or we have had to wait
2824 // for the controlling driver to change the state. Here we see if we need
2825 // to wait for power to settle before continuing. If not, we continue
2826 // processing (acknowledging our preparedness to the parent).
2827 // If so, we wait and continue later.
2828 //*********************************************************************************
2830 void IOService::ParentDownWaitForPowerSettle_Delayed ( void )
2832 priv
->settle_time
= compute_settle_time();
2833 if ( priv
->settle_time
== 0 )
2835 ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed();
2837 priv
->machine_state
= kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
;
2838 startSettleTimer(priv
->settle_time
);
2843 //*********************************************************************************
2844 // ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
2846 // Power has settled on a power change initiated by our parent. Here we
2847 // notify interested parties.
2848 //*********************************************************************************
2850 void IOService::ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed ( void )
2852 IORegistryEntry
*nub
;
2855 // in case they don't all ack
2856 priv
->machine_state
= kIOPM_ParentDownAcknowledgeChange_Delayed
;
2857 if ( notifyAll(false) == IOPMAckImplied
) {
2858 nub
= priv
->head_note_parent
;
2861 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2863 parent
->acknowledgePowerChange((IOService
*)nub
);
2868 // If we are waiting for responses, execution will resume via
2869 // all_acked() or ack timeout in ParentDownAcknowledgeChange_Delayed.
2870 // Notice the duplication of code just above and in ParentDownAcknowledgeChange_Delayed.
2874 //*********************************************************************************
2875 // ParentDownAcknowledgeChange_Delayed
2877 // We had to wait for it, but all parties have acknowledged our post-change
2878 // notification of a power lowering initiated by the parent.
2879 // Here we acknowledge the parent.
2880 // We are done with this change note, and we can start on the next one.
2881 //*********************************************************************************
2883 void IOService::ParentDownAcknowledgeChange_Delayed ( void )
2885 IORegistryEntry
*nub
;
2888 nub
= priv
->head_note_parent
;
2891 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2894 parent
->acknowledgePowerChange((IOService
*)nub
);
2901 //*********************************************************************************
2902 // ParentUpSetPowerState_Delayed
2904 // Our parent has informed us via powerStateDidChange that it has
2905 // raised the power in our power domain, and we have had to wait
2906 // for some interested party to acknowledge our notification.
2907 // Here we instruct our controlling
2908 // driver to program the hardware to take advantage of the higher domain
2909 // power. If it does so, we continue processing
2910 // (waiting for settle and notifying interested parties post-change.)
2911 // If it doesn't, we have to wait for it to acknowledge and then continue.
2912 //*********************************************************************************
2914 void IOService::ParentUpSetPowerState_Delayed ( void )
2916 priv
->machine_state
= kIOPM_ParentUpWaitForSettleTime_Delayed
;
2918 IOLockLock(priv
->our_lock
);
2920 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2922 // it did it, carry on
2923 IOLockUnlock(priv
->our_lock
);
2924 ParentUpWaitForSettleTime_Delayed();
2926 // it didn't, wait for it
2927 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2929 IOLockUnlock(priv
->our_lock
);
2934 //*********************************************************************************
2935 // ParentUpSetPowerState_Immediate
2937 // Our parent has informed us via powerStateDidChange that it has
2938 // raised the power in our power domain. Here we instruct our controlling
2939 // driver to program the hardware to take advantage of the higher domain
2940 // power. If it does so, we continue processing
2941 // (waiting for settle and notifying interested parties post-change.)
2942 // If it doesn't, we have to wait for it to acknowledge and then continue.
2943 //*********************************************************************************
2945 IOReturn
IOService::ParentUpSetPowerState_Immediate ( void )
2947 priv
->machine_state
= kIOPM_ParentUpWaitForSettleTime_Delayed
;
2949 IOLockLock(priv
->our_lock
);
2951 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
)
2953 // it did it, carry on
2954 IOLockUnlock(priv
->our_lock
);
2955 return ParentUpWaitForSettleTime_Immediate();
2958 // it didn't, wait for it
2959 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2961 IOLockUnlock(priv
->our_lock
);
2962 return IOPMWillAckLater
;
2967 //*********************************************************************************
2968 // ParentUpWaitForSettleTime_Immediate
2970 // Our controlling driver has changed power state on the hardware
2971 // during a power raise initiated by the parent. Here we see if we need to wait
2972 // for power to settle before continuing. If not, we continue processing
2973 // (notifying interested parties post-change). If so, we wait and
2975 //*********************************************************************************
2977 IOReturn
IOService::ParentUpWaitForSettleTime_Immediate ( void )
2979 priv
->settle_time
= compute_settle_time();
2980 if ( priv
->settle_time
== 0 )
2982 return ParentUpNotifyInterestedDriversDidChange_Immediate();
2984 priv
->machine_state
= kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed
;
2985 startSettleTimer(priv
->settle_time
);
2986 return IOPMWillAckLater
;
2991 //*********************************************************************************
2992 // ParentUpWaitForSettleTime_Delayed
2994 // Our controlling driver has changed power state on the hardware
2995 // during a power raise initiated by the parent, but we had to wait for it.
2996 // Here we see if we need to wait for power to settle before continuing.
2997 // If not, we continue processing (notifying interested parties post-change).
2998 // If so, we wait and continue later.
2999 //*********************************************************************************
3001 void IOService::ParentUpWaitForSettleTime_Delayed ( void )
3003 priv
->settle_time
= compute_settle_time();
3004 if ( priv
->settle_time
== 0 )
3006 ParentUpNotifyInterestedDriversDidChange_Delayed();
3008 priv
->machine_state
= kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed
;
3009 startSettleTimer(priv
->settle_time
);
3014 //*********************************************************************************
3015 // ParentUpNotifyInterestedDriversDidChange_Immediate
3017 // No power settling was required on a power raise initiated by the parent.
3018 // Here we notify all our interested parties post-change. If they all acknowledge,
3019 // we're done with this change note, and we can start on the next one.
3020 // Otherwise we have to wait for acknowledgements and finish up later.
3021 //*********************************************************************************
3023 IOReturn
IOService::ParentUpNotifyInterestedDriversDidChange_Immediate ( void )
3027 // in case they don't all ack
3028 priv
->machine_state
= kIOPM_ParentUpAcknowledgePowerChange_Delayed
;
3029 if ( notifyAll(false) == IOPMAckImplied
)
3031 nub
= priv
->head_note_parent
;
3035 return IOPMAckImplied
;
3037 // If we are waiting for responses, execution will resume via
3038 // all_acked() or ack timeout in ParentUpAcknowledgePowerChange_Delayed.
3039 return IOPMWillAckLater
;
3043 //*********************************************************************************
3044 // ParentUpNotifyInterestedDriversDidChange_Delayed
3046 // Power has settled on a power raise initiated by the parent.
3047 // Here we notify all our interested parties post-change. If they all acknowledge,
3048 // we're done with this change note, and we can start on the next one.
3049 // Otherwise we have to wait for acknowledgements and finish up later.
3050 //*********************************************************************************
3052 void IOService::ParentUpNotifyInterestedDriversDidChange_Delayed ( void )
3054 // in case they don't all ack
3055 priv
->machine_state
= kIOPM_ParentUpAcknowledgePowerChange_Delayed
;
3056 if ( notifyAll(false) == IOPMAckImplied
)
3058 ParentUpAcknowledgePowerChange_Delayed();
3060 // If we are waiting for responses, execution will resume via
3061 // all_acked() or ack timeout in ParentUpAcknowledgePowerChange_Delayed.
3065 //*********************************************************************************
3066 // ParentUpAcknowledgePowerChange_Delayed
3068 // All parties have acknowledged our post-change notification of a power
3069 // raising initiated by the parent. Here we acknowledge the parent.
3070 // We are done with this change note, and we can start on the next one.
3071 //*********************************************************************************
3073 void IOService::ParentUpAcknowledgePowerChange_Delayed ( void )
3075 IORegistryEntry
*nub
;
3078 nub
= priv
->head_note_parent
;
3081 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
3084 parent
->acknowledgePowerChange((IOService
*)nub
);
3091 //*********************************************************************************
3094 // A power change is complete, and the used post-change note is at
3095 // the head of the queue. Remove it and set myCurrentState to the result
3096 // of the change. Start up the next change in queue.
3097 //*********************************************************************************
3099 void IOService::all_done ( void )
3101 unsigned long previous_state
;
3102 IORegistryEntry
*nub
;
3105 priv
->machine_state
= kIOPM_Finished
;
3108 if ( priv
->head_note_flags
& IOPMWeInitiated
)
3110 // could our driver switch to the new state?
3111 if ( !( priv
->head_note_flags
& IOPMNotDone
) )
3113 // yes, did power raise?
3114 if ( pm_vars
->myCurrentState
< priv
->head_note_state
)
3116 // yes, inform clients and apps
3117 tellChangeUp (priv
->head_note_state
);
3119 // no, if this lowers our
3120 if ( ! priv
->we_are_root
)
3122 // power requirements, tell the parent
3123 ask_parent(priv
->head_note_state
);
3126 previous_state
= pm_vars
->myCurrentState
;
3128 pm_vars
->myCurrentState
= priv
->head_note_state
;
3129 priv
->imminentState
= pm_vars
->myCurrentState
;
3130 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
3131 // inform subclass policy-maker
3132 powerChangeDone(previous_state
);
3136 // parent's power change
3137 if ( priv
->head_note_flags
& IOPMParentInitiated
)
3139 if ( ((priv
->head_note_flags
& IOPMDomainWillChange
) && (pm_vars
->myCurrentState
>= priv
->head_note_state
)) ||
3140 ((priv
->head_note_flags
& IOPMDomainDidChange
) && (pm_vars
->myCurrentState
< priv
->head_note_state
)) )
3143 if ( pm_vars
->myCurrentState
< priv
->head_note_state
)
3145 // yes, inform clients and apps
3146 tellChangeUp (priv
->head_note_state
);
3149 previous_state
= pm_vars
->myCurrentState
;
3150 pm_vars
->myCurrentState
= priv
->head_note_state
;
3151 priv
->imminentState
= pm_vars
->myCurrentState
;
3152 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(priv
->head_note_domainState
);
3154 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
3155 // inform subclass policy-maker
3156 powerChangeDone(previous_state
);
3160 IOLockLock(priv
->queue_lock
);
3161 // we're done with this
3162 priv
->changeList
->releaseHeadChangeNote();
3164 // start next one in queue
3165 priv
->head_note
= priv
->changeList
->currentChange();
3166 if ( priv
->head_note
!= -1 )
3169 IOLockUnlock(priv
->queue_lock
);
3170 if (priv
->changeList
->changeNote
[priv
->head_note
].flags
& IOPMWeInitiated
)
3172 start_our_change(priv
->head_note
);
3174 nub
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
3175 if ( start_parent_change(priv
->head_note
) == IOPMAckImplied
)
3177 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
3180 parent
->acknowledgePowerChange((IOService
*)nub
);
3186 IOLockUnlock(priv
->queue_lock
);
3192 //*********************************************************************************
3195 // A driver or child has acknowledged our notification of an upcoming power
3196 // change, and this acknowledgement is the last one pending
3197 // before we change power or after changing power.
3199 //*********************************************************************************
3201 void IOService::all_acked ( void )
3203 getPMRootDomain()->getPMArbiter()->allAckedOccurred(this);
3208 void IOService::all_acked_threaded ( void )
3210 switch (priv
->machine_state
) {
3211 case kIOPM_OurChangeSetPowerState
:
3212 OurChangeSetPowerState();
3214 case kIOPM_OurChangeFinish
:
3217 case kIOPM_ParentDownSetPowerState_Delayed
:
3218 ParentDownSetPowerState_Delayed();
3220 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
3221 ParentDownAcknowledgeChange_Delayed();
3223 case kIOPM_ParentUpSetPowerState_Delayed
:
3224 ParentUpSetPowerState_Delayed();
3226 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
3227 ParentUpAcknowledgePowerChange_Delayed();
3232 //*********************************************************************************
3233 // settleTimerExpired
3235 // Power has settled after our last change. Notify interested parties that
3236 // there is a new power state.
3237 //*********************************************************************************
3239 void IOService::settleTimerExpired ( void )
3241 if ( ! initialized
)
3247 switch (priv
->machine_state
) {
3248 case kIOPM_OurChangeNotifyInterestedDriversDidChange
:
3249 OurChangeNotifyInterestedDriversDidChange();
3251 case kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed
:
3252 ParentDownNotifyDidChangeAndAcknowledgeChange_Delayed();
3254 case kIOPM_ParentUpNotifyInterestedDriversDidChange_Delayed
:
3255 ParentUpNotifyInterestedDriversDidChange_Delayed();
3261 //*********************************************************************************
3262 // compute_settle_time
3264 // Compute the power-settling delay in microseconds for the
3265 // change from myCurrentState to head_note_state.
3266 //*********************************************************************************
3268 unsigned long IOService::compute_settle_time ( void )
3270 unsigned long totalTime
;
3273 // compute total time to attain the new state
3275 i
= pm_vars
->myCurrentState
;
3277 // we're lowering power
3278 if ( priv
->head_note_state
< pm_vars
->myCurrentState
)
3280 while ( i
> priv
->head_note_state
)
3282 totalTime
+= pm_vars
->thePowerStates
[i
].settleDownTime
;
3287 // we're raising power
3288 if ( priv
->head_note_state
> pm_vars
->myCurrentState
)
3290 while ( i
< priv
->head_note_state
)
3292 totalTime
+= pm_vars
->thePowerStates
[i
+1].settleUpTime
;
3301 //*********************************************************************************
3304 // Enter with a power-settling delay in microseconds and start a nano-second
3305 // timer for that delay.
3306 //*********************************************************************************
3308 IOReturn
IOService::startSettleTimer ( unsigned long delay
)
3310 AbsoluteTime deadline
;
3312 clock_interval_to_deadline(delay
, kMicrosecondScale
, &deadline
);
3314 thread_call_enter_delayed(priv
->settleTimer
, deadline
);
3319 //*********************************************************************************
3322 // The acknowledgement timeout periodic timer has ticked.
3323 // If we are awaiting acks for a power change notification,
3324 // we decrement the timer word of each interested driver which hasn't acked.
3325 // If a timer word becomes zero, we pretend the driver aknowledged.
3326 // If we are waiting for the controlling driver to change the power
3327 // state of the hardware, we decrement its timer word, and if it becomes
3328 // zero, we pretend the driver acknowledged.
3329 //*********************************************************************************
3331 void IOService::ack_timer_ticked ( void )
3333 IOPMinformee
* nextObject
;
3335 if ( ! initialized
)
3341 if (! acquire_lock() )
3346 switch (priv
->machine_state
) {
3347 case kIOPM_OurChangeWaitForPowerSettle
:
3348 case kIOPM_ParentDownWaitForPowerSettle_Delayed
:
3349 case kIOPM_ParentUpWaitForSettleTime_Delayed
:
3350 // are we waiting for our driver to make its change?
3351 if ( priv
->driver_timer
!= 0 ) {
3353 priv
->driver_timer
-= 1;
3354 // it's tardy, we'll go on without it
3355 if ( priv
->driver_timer
== 0 )
3357 IOUnlock(priv
->our_lock
);
3358 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCtrlDriverTardy
,0,0);
3361 // still waiting, set timer again
3363 IOUnlock(priv
->our_lock
);
3367 IOUnlock(priv
->our_lock
);
3371 case kIOPM_OurChangeSetPowerState
:
3372 case kIOPM_OurChangeFinish
:
3373 case kIOPM_ParentDownSetPowerState_Delayed
:
3374 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
3375 case kIOPM_ParentUpSetPowerState_Delayed
:
3376 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
3377 // are we waiting for interested parties to acknowledge?
3378 if (priv
->head_note_pendingAcks
!= 0 )
3380 // yes, go through the list of interested drivers
3381 nextObject
= priv
->interestedDrivers
->firstInList();
3382 // and check each one
3383 while ( nextObject
!= NULL
)
3385 if ( nextObject
->timer
> 0 )
3387 nextObject
->timer
-= 1;
3388 // this one should have acked by now
3389 if ( nextObject
->timer
== 0 )
3391 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogIntDriverTardy
,0,0);
3392 //kprintf("interested driver tardy: %s\n",nextObject->whatObject->getName());
3393 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
3396 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
3399 // is that the last?
3400 if ( priv
->head_note_pendingAcks
== 0 )
3402 IOUnlock(priv
->our_lock
);
3403 // yes, we can continue
3406 // no, set timer again
3408 IOUnlock(priv
->our_lock
);
3411 IOUnlock(priv
->our_lock
);
3415 // apps didn't respond to parent-down notification
3416 case kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate
:
3417 IOUnlock(priv
->our_lock
);
3418 IOLockLock(priv
->flags_lock
);
3419 if (pm_vars
->responseFlags
)
3421 // get rid of this stuff
3422 pm_vars
->responseFlags
->release();
3423 pm_vars
->responseFlags
= NULL
;
3425 IOLockUnlock(priv
->flags_lock
);
3426 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,5);
3427 // carry on with the change
3428 ParentDownTellPriorityClientsPowerDown_Delayed();
3431 case kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
:
3432 IOUnlock(priv
->our_lock
);
3433 IOLockLock(priv
->flags_lock
);
3434 if (pm_vars
->responseFlags
)
3436 // get rid of this stuff
3437 pm_vars
->responseFlags
->release();
3438 pm_vars
->responseFlags
= NULL
;
3440 IOLockUnlock(priv
->flags_lock
);
3441 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,1);
3442 // carry on with the change
3443 ParentDownNotifyInterestedDriversWillChange_Delayed();
3446 case kIOPM_OurChangeTellClientsPowerDown
:
3447 // apps didn't respond to our power-down request
3448 IOUnlock(priv
->our_lock
);
3449 IOLockLock(priv
->flags_lock
);
3450 if (pm_vars
->responseFlags
)
3452 // get rid of this stuff
3453 pm_vars
->responseFlags
->release();
3454 pm_vars
->responseFlags
= NULL
;
3456 IOLockUnlock(priv
->flags_lock
);
3457 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,2);
3458 // rescind the request
3459 tellNoChangeDown(priv
->head_note_state
);
3460 // mark the change note un-actioned
3461 priv
->head_note_flags
|= IOPMNotDone
;
3466 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
3467 // clients didn't respond to our power-down note
3468 IOUnlock(priv
->our_lock
);
3469 IOLockLock(priv
->flags_lock
);
3470 if (pm_vars
->responseFlags
)
3472 // get rid of this stuff
3473 pm_vars
->responseFlags
->release();
3474 pm_vars
->responseFlags
= NULL
;
3476 IOLockUnlock(priv
->flags_lock
);
3477 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,4);
3478 // carry on with the change
3479 OurChangeTellPriorityClientsPowerDown();
3482 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
3483 // apps didn't respond to our power-down notification
3484 IOUnlock(priv
->our_lock
);
3485 IOLockLock(priv
->flags_lock
);
3486 if (pm_vars
->responseFlags
)
3488 // get rid of this stuff
3489 pm_vars
->responseFlags
->release();
3490 pm_vars
->responseFlags
= NULL
;
3492 IOLockUnlock(priv
->flags_lock
);
3493 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,3);
3494 // carry on with the change
3495 OurChangeNotifyInterestedDriversWillChange();
3499 // not waiting for acks
3500 IOUnlock(priv
->our_lock
);
3506 //*********************************************************************************
3509 //*********************************************************************************
3511 void IOService::start_ack_timer ( void )
3513 AbsoluteTime deadline
;
3515 clock_interval_to_deadline(ACK_TIMER_PERIOD
, kNanosecondScale
, &deadline
);
3517 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
3521 //*********************************************************************************
3524 //*********************************************************************************
3526 void IOService::stop_ack_timer ( void )
3528 thread_call_cancel(priv
->ackTimer
);
3532 //*********************************************************************************
3533 // c-language timer expiration functions
3535 //*********************************************************************************
3537 static void ack_timer_expired ( thread_call_param_t us
)
3539 ((IOService
*)us
)->ack_timer_ticked();
3543 static void settle_timer_expired ( thread_call_param_t us
)
3545 ((IOService
*)us
)->settleTimerExpired();
3549 //*********************************************************************************
3550 // add_child_to_active_change
3552 // A child has just registered with us. If there is
3553 // currently a change in progress, get the new party involved: if we
3554 // have notified all parties and are waiting for acks, notify the new
3556 //*********************************************************************************
3558 IOReturn
IOService::add_child_to_active_change ( IOPowerConnection
* newObject
)
3560 if (! acquire_lock() )
3565 switch (priv
->machine_state
)
3567 case kIOPM_OurChangeSetPowerState
:
3568 case kIOPM_ParentDownSetPowerState_Delayed
:
3569 case kIOPM_ParentUpSetPowerState_Delayed
:
3570 // one for this child and one to prevent
3571 OSAddAtomic(2, (SInt32
*)&priv
->head_note_pendingAcks
);
3572 // incoming acks from changing our state
3573 IOUnlock(priv
->our_lock
);
3574 notifyChild(newObject
, true);
3575 if (! acquire_lock() )
3578 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
3581 // are we still waiting for acks?
3582 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
3583 if ( priv
->head_note_pendingAcks
== 0 )
3585 // no, stop the timer
3587 IOUnlock(priv
->our_lock
);
3589 // and now we can continue
3594 case kIOPM_OurChangeFinish
:
3595 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
3596 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
3597 // one for this child and one to prevent
3598 OSAddAtomic(2, (SInt32
*)&priv
->head_note_pendingAcks
);
3599 // incoming acks from changing our state
3600 IOUnlock(priv
->our_lock
);
3601 notifyChild(newObject
, false);
3602 if (! acquire_lock() )
3605 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
3608 // are we still waiting for acks?
3609 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
3610 if ( priv
->head_note_pendingAcks
== 0 )
3612 // no, stop the timer
3614 IOUnlock(priv
->our_lock
);
3616 // and now we can continue
3622 IOUnlock(priv
->our_lock
);
3627 //*********************************************************************************
3628 // add_driver_to_active_change
3630 // An interested driver has just registered with us. If there is
3631 // currently a change in progress, get the new party involved: if we
3632 // have notified all parties and are waiting for acks, notify the new
3634 //*********************************************************************************
3636 IOReturn
IOService::add_driver_to_active_change ( IOPMinformee
* newObject
)
3638 if (! acquire_lock() )
3643 switch (priv
->machine_state
) {
3644 case kIOPM_OurChangeSetPowerState
:
3645 case kIOPM_ParentDownSetPowerState_Delayed
:
3646 case kIOPM_ParentUpSetPowerState_Delayed
:
3647 // one for this driver and one to prevent
3648 OSAddAtomic(2, (SInt32
*)&priv
->head_note_pendingAcks
);
3649 // incoming acks from changing our state
3650 IOUnlock(priv
->our_lock
);
3651 // inform the driver
3652 inform(newObject
, true);
3653 if (! acquire_lock() )
3656 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
3659 // are we still waiting for acks?
3660 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
3661 if ( priv
->head_note_pendingAcks
== 0 )
3663 // no, stop the timer
3665 IOUnlock(priv
->our_lock
);
3667 // and now we can continue
3672 case kIOPM_OurChangeFinish
:
3673 case kIOPM_ParentDownAcknowledgeChange_Delayed
:
3674 case kIOPM_ParentUpAcknowledgePowerChange_Delayed
:
3675 // one for this driver and one to prevent
3676 OSAddAtomic(2, (SInt32
*)&priv
->head_note_pendingAcks
);
3677 // incoming acks from changing our state
3678 IOUnlock(priv
->our_lock
);
3679 // inform the driver
3680 inform(newObject
, false);
3681 if (! acquire_lock() ) {
3683 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
3686 // are we still waiting for acks?
3687 OSAddAtomic(-1, (SInt32
*)&priv
->head_note_pendingAcks
);
3688 if ( priv
->head_note_pendingAcks
== 0 ) {
3689 // no, stop the timer
3691 IOUnlock(priv
->our_lock
);
3693 // and now we can continue
3699 IOUnlock(priv
->our_lock
);
3704 //*********************************************************************************
3705 // start_parent_change
3707 // Here we begin the processing of a change note initiated by our parent
3708 // which is at the head of the queue.
3710 // It is possible for the change to be processed to completion and removed from the queue.
3711 // There are several possible interruptions to the processing, though, and they are:
3712 // we may have to wait for interested parties to acknowledge our pre-change notification,
3713 // we may have to wait for our controlling driver to change the hardware power state,
3714 // there may be a settling time after changing the hardware power state,
3715 // we may have to wait for interested parties to acknowledge our post-change notification,
3716 // we may have to wait for the acknowledgement timer expiration to substitute for the
3717 // acknowledgement from a failing driver.
3718 //*********************************************************************************
3720 IOReturn
IOService::start_parent_change ( unsigned long queue_head
)
3722 priv
->head_note
= queue_head
;
3723 priv
->head_note_flags
= priv
-> changeList
->changeNote
[priv
->head_note
].flags
;
3724 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3725 priv
->imminentState
= priv
->head_note_state
;
3726 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3727 priv
->head_note_domainState
= priv
->changeList
->changeNote
[priv
->head_note
].domainState
;
3728 priv
->head_note_parent
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
3729 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3731 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartParentChange
,
3732 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3734 // if we need something and haven't told the parent, do so
3735 ask_parent( priv
->ourDesiredPowerState
);
3737 // power domain is lowering
3738 if ( priv
->head_note_state
< pm_vars
->myCurrentState
)
3740 setParentInfo(priv
->changeList
->changeNote
[priv
->head_note
].singleParentState
,priv
->head_note_parent
);
3741 priv
->initial_change
= false;
3742 // tell apps and kernel clients
3743 priv
->machine_state
= kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate
;
3745 // are we waiting for responses?
3746 if ( tellChangeDown1(priv
->head_note_state
) )
3748 // no, notify priority clients
3749 return ParentDownTellPriorityClientsPowerDown_Immediate();
3752 return IOPMWillAckLater
;
3755 // parent is raising power, we may or may not
3756 if ( priv
->head_note_state
> pm_vars
->myCurrentState
)
3758 if ( priv
->ourDesiredPowerState
> pm_vars
->myCurrentState
)
3760 if ( priv
->ourDesiredPowerState
< priv
->head_note_state
)
3762 // we do, but not all the way
3763 priv
->head_note_state
= priv
->ourDesiredPowerState
;
3764 priv
->imminentState
= priv
->head_note_state
;
3765 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3766 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3767 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3771 priv
->head_note_state
= pm_vars
->myCurrentState
;
3772 priv
->imminentState
= priv
->head_note_state
;
3773 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3774 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3775 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3779 if ( (priv
->head_note_state
> pm_vars
->myCurrentState
) &&
3780 (priv
->head_note_flags
& IOPMDomainDidChange
) )
3783 priv
->initial_change
= false;
3784 priv
->machine_state
= kIOPM_ParentUpSetPowerState_Delayed
;
3785 if ( notifyAll(true) == IOPMAckImplied
) {
3786 return ParentUpSetPowerState_Immediate();
3788 // they didn't all ack
3789 return IOPMWillAckLater
;
3793 // a null change or power will go up
3794 return IOPMAckImplied
;
3798 //*********************************************************************************
3801 // Here we begin the processing of a change note initiated by us
3802 // which is at the head of the queue.
3804 // It is possible for the change to be processed to completion and removed from the queue.
3805 // There are several possible interruptions to the processing, though, and they are:
3806 // we may have to wait for interested parties to acknowledge our pre-change notification,
3807 // changes initiated by the parent will wait in the middle for powerStateDidChange,
3808 // we may have to wait for our controlling driver to change the hardware power state,
3809 // there may be a settling time after changing the hardware power state,
3810 // we may have to wait for interested parties to acknowledge our post-change notification,
3811 // we may have to wait for the acknowledgement timer expiration to substitute for the
3812 // acknowledgement from a failing driver.
3813 //*********************************************************************************
3815 void IOService::start_our_change ( unsigned long queue_head
)
3817 priv
->head_note
= queue_head
;
3818 priv
->head_note_flags
= priv
->changeList
->changeNote
[priv
->head_note
].flags
;
3819 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3820 priv
->imminentState
= priv
->head_note_state
;
3821 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3822 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3824 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartDeviceChange
,
3825 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3827 // can our driver switch to the new state?
3828 if ( priv
->head_note_capabilityFlags
& IOPMNotAttainable
)
3830 // no, ask the parent to do it then
3831 if ( ! priv
->we_are_root
)
3833 ask_parent(priv
->head_note_state
);
3835 // mark the change note un-actioned
3836 priv
-> head_note_flags
|= IOPMNotDone
;
3842 // is there enough power in the domain?
3843 if ( (pm_vars
->maxCapability
< priv
->head_note_state
) && (! priv
->we_are_root
) )
3845 // no, ask the parent to raise it
3846 if ( ! priv
->we_are_root
)
3848 ask_parent(priv
->head_note_state
);
3850 // no, mark the change note un-actioned
3851 priv
->head_note_flags
|= IOPMNotDone
;
3853 // till the parent raises power
3858 if ( ! priv
->initial_change
)
3860 if ( priv
->head_note_state
== pm_vars
->myCurrentState
)
3862 // we initiated a null change; forget it
3867 priv
->initial_change
= false;
3870 if ( priv
->head_note_state
< pm_vars
->myCurrentState
)
3872 // yes, in case we have to wait for acks
3873 priv
->machine_state
= kIOPM_OurChangeTellClientsPowerDown
;
3874 pm_vars
->doNotPowerDown
= false;
3876 // ask apps and kernel clients if we can drop power
3877 pm_vars
->outofbandparameter
= kNotifyApps
;
3878 if ( askChangeDown(priv
->head_note_state
) )
3880 // don't have to wait, did any clients veto?
3881 if ( pm_vars
->doNotPowerDown
)
3883 // yes, rescind the warning
3884 tellNoChangeDown(priv
->head_note_state
);
3885 // mark the change note un-actioned
3886 priv
-> head_note_flags
|= IOPMNotDone
;
3890 // no, tell'em we're dropping power
3891 OurChangeTellClientsPowerDown();
3895 // we are raising power
3896 if ( ! priv
->we_are_root
)
3898 // if this changes our power requirement, tell the parent
3899 ask_parent(priv
->head_note_state
);
3901 // in case they don't all ack
3902 priv
->machine_state
= kIOPM_OurChangeSetPowerState
;
3904 // notify interested drivers and children
3905 if ( notifyAll(true) == IOPMAckImplied
)
3907 OurChangeSetPowerState();
3913 //*********************************************************************************
3916 // Call the power domain parent to ask for a higher power state in the domain
3917 // or to suggest a lower power state.
3918 //*********************************************************************************
3920 IOReturn
IOService::ask_parent ( unsigned long requestedState
)
3924 IOPowerConnection
*connection
;
3926 unsigned long ourRequest
= pm_vars
->thePowerStates
[requestedState
].inputPowerRequirement
;
3928 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp
| kIOPMPreventIdleSleep
) )
3930 ourRequest
|= kIOPMPreventIdleSleep
;
3932 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp2
| kIOPMPreventSystemSleep
) )
3934 ourRequest
|= kIOPMPreventSystemSleep
;
3937 // is this a new desire?
3938 if ( priv
->previousRequest
== ourRequest
)
3940 // no, the parent knows already, just return
3944 if ( priv
->we_are_root
)
3948 priv
->previousRequest
= ourRequest
;
3950 iter
= getParentIterator(gIOPowerPlane
);
3954 while ( (next
= iter
->getNextObject()) )
3956 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
3958 parent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
3960 if ( parent
->requestPowerDomainState(ourRequest
,connection
,IOPMLowestState
)!= IOPMNoErr
)
3962 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDenied
,
3963 (unsigned long)priv
->previousRequest
,0);
3976 //*********************************************************************************
3979 // Call the controlling driver and have it change the power state of the
3980 // hardware. If it returns IOPMAckImplied, the change is complete, and
3981 // we return IOPMAckImplied. Otherwise, it will ack when the change
3982 // is done; we return IOPMWillAckLater.
3983 //*********************************************************************************
3984 IOReturn
IOService::instruct_driver ( unsigned long newState
)
3988 // can our driver switch to the desired state?
3989 if ( pm_vars
->thePowerStates
[newState
].capabilityFlags
& IOPMNotAttainable
)
3992 return IOPMAckImplied
;
3995 priv
->driver_timer
= -1;
3998 IOLockUnlock(priv
->our_lock
);
3999 OUR_PMLog( kPMLogProgramHardware
, (UInt32
) this, newState
);
4000 delay
= pm_vars
->theControllingDriver
->setPowerState( newState
,this );
4001 OUR_PMLog((UInt32
) -kPMLogProgramHardware
, (UInt32
) this, (UInt32
) delay
);
4002 IOLockLock(priv
->our_lock
);
4005 if ( delay
== IOPMAckImplied
)
4007 priv
->driver_timer
= 0;
4008 return IOPMAckImplied
;
4011 // it acked behind our back
4012 if ( priv
->driver_timer
== 0 )
4014 return IOPMAckImplied
;
4020 return IOPMAckImplied
;
4024 priv
->driver_timer
= (delay
/ ( ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
4025 return IOPMWillAckLater
;
4029 //*********************************************************************************
4032 // We are acquiring the lock we use to protect our queue head from
4033 // simutaneous access by a thread which calls acknowledgePowerStateChange
4034 // or acknowledgeSetPowerState and the ack timer expiration thread.
4035 // Return TRUE if we acquire the lock, and the queue head didn't change
4036 // while we were acquiring the lock (and maybe blocked).
4037 // If there is no queue head, or it changes while we are blocked,
4038 // return FALSE with the lock unlocked.
4039 //*********************************************************************************
4041 bool IOService::acquire_lock ( void )
4043 long current_change_note
;
4045 current_change_note
= priv
->head_note
;
4046 if ( current_change_note
== -1 ) {
4050 IOTakeLock(priv
->our_lock
);
4051 if ( current_change_note
== priv
->head_note
)
4055 // we blocked and something changed radically
4056 // so there's nothing to do any more
4057 IOUnlock(priv
->our_lock
);
4063 //*********************************************************************************
4066 // Ask registered applications and kernel clients if we can change to a lower
4069 // Subclass can override this to send a different message type. Parameter is
4070 // the destination state number.
4072 // Return true if we don't have to wait for acknowledgements
4073 //*********************************************************************************
4075 bool IOService::askChangeDown ( unsigned long stateNum
)
4077 return tellClientsWithResponse(kIOMessageCanDevicePowerOff
);
4081 //*********************************************************************************
4084 // Notify registered applications and kernel clients that we are definitely
4087 // Return true if we don't have to wait for acknowledgements
4088 //*********************************************************************************
4090 bool IOService::tellChangeDown1 ( unsigned long stateNum
)
4092 pm_vars
->outofbandparameter
= kNotifyApps
;
4093 return tellChangeDown(stateNum
);
4097 //*********************************************************************************
4100 // Notify priority clients that we are definitely dropping power.
4102 // Return true if we don't have to wait for acknowledgements
4103 //*********************************************************************************
4105 bool IOService::tellChangeDown2 ( unsigned long stateNum
)
4107 pm_vars
->outofbandparameter
= kNotifyPriority
;
4108 return tellChangeDown(stateNum
);
4112 //*********************************************************************************
4115 // Notify registered applications and kernel clients that we are definitely
4118 // Subclass can override this to send a different message type. Parameter is
4119 // the destination state number.
4121 // Return true if we don't have to wait for acknowledgements
4122 //*********************************************************************************
4124 bool IOService::tellChangeDown ( unsigned long stateNum
)
4126 return tellClientsWithResponse(kIOMessageDeviceWillPowerOff
);
4130 //*********************************************************************************
4131 // tellClientsWithResponse
4133 // Notify registered applications and kernel clients that we are definitely
4136 // Return true if we don't have to wait for acknowledgements
4137 //*********************************************************************************
4139 bool IOService::tellClientsWithResponse ( int messageType
)
4141 struct context theContext
;
4142 AbsoluteTime deadline
;
4145 pm_vars
->responseFlags
= OSArray::withCapacity( 1 );
4146 pm_vars
->serialNumber
+= 1;
4148 theContext
.responseFlags
= pm_vars
->responseFlags
;
4149 theContext
.serialNumber
= pm_vars
->serialNumber
;
4150 theContext
.flags_lock
= priv
->flags_lock
;
4151 theContext
.counter
= 1;
4152 theContext
.msgType
= messageType
;
4153 theContext
.us
= this;
4154 theContext
.maxTimeRequested
= 0;
4155 theContext
.stateNumber
= priv
->head_note_state
;
4156 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
4158 IOLockLock(priv
->flags_lock
);
4160 // position zero is false to
4161 // prevent allowCancelCommon from succeeding
4162 aBool
= OSBoolean::withBoolean(false);
4163 theContext
.responseFlags
->setObject(0,aBool
);
4165 IOLockUnlock(priv
->flags_lock
);
4167 switch ( pm_vars
->outofbandparameter
) {
4169 applyToInterested(gIOAppPowerStateInterest
,tellAppWithResponse
,(void *)&theContext
);
4170 applyToInterested(gIOGeneralInterest
,tellClientWithResponse
,(void *)&theContext
);
4172 case kNotifyPriority
:
4173 applyToInterested(gIOPriorityPowerStateInterest
,tellClientWithResponse
,(void *)&theContext
);
4177 if (! acquire_lock() )
4181 IOLockLock(priv
->flags_lock
);
4182 // now fix position zero
4183 aBool
= OSBoolean::withBoolean(true);
4184 theContext
.responseFlags
->replaceObject(0,aBool
);
4186 IOLockUnlock(priv
->flags_lock
);
4188 // do we have to wait for somebody?
4189 if ( ! checkForDone() )
4191 // yes, start the ackTimer
4192 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,theContext
.maxTimeRequested
,0);
4193 clock_interval_to_deadline(theContext
.maxTimeRequested
/ 1000, kMillisecondScale
, &deadline
);
4195 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
4197 IOUnlock(priv
->our_lock
);
4201 IOUnlock(priv
->our_lock
);
4202 IOLockLock(priv
->flags_lock
);
4204 // everybody responded
4205 pm_vars
->responseFlags
->release();
4206 pm_vars
->responseFlags
= NULL
;
4207 IOLockUnlock(priv
->flags_lock
);
4213 //*********************************************************************************
4214 // tellAppWithResponse
4216 // We send a message to an application, and we expect a response, so we compute a
4217 // cookie we can identify the response with.
4218 //*********************************************************************************
4219 void tellAppWithResponse ( OSObject
* object
, void * context
)
4221 struct context
*theContext
= (struct context
*)context
;
4223 IOPMprot
*pm_vars
= theContext
->us
->pm_vars
;
4225 if( OSDynamicCast( IOService
, object
) )
4227 // Automatically 'ack' in kernel clients
4228 IOLockLock(theContext
->flags_lock
);
4229 aBool
= OSBoolean::withBoolean(true);
4230 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
4232 IOLockUnlock(theContext
->flags_lock
);
4234 const char *who
= ((IOService
*) object
)->getName();
4235 pm_vars
->thePlatform
->PMLog(who
,
4236 kPMLogClientAcknowledge
, theContext
->msgType
, * (UInt32
*) object
);
4238 UInt32 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16)
4239 + (theContext
->counter
& 0xFFFF);
4240 IOLockLock(theContext
->flags_lock
);
4241 aBool
= OSBoolean::withBoolean(false);
4242 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
4244 IOLockUnlock(theContext
->flags_lock
);
4246 OUR_PMLog(kPMLogAppNotify
, theContext
->msgType
, refcon
);
4247 theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)refcon
);
4248 if ( theContext
->maxTimeRequested
< k30seconds
)
4250 theContext
->maxTimeRequested
= k30seconds
;
4253 theContext
->counter
+= 1;
4256 //*********************************************************************************
4257 // tellClientWithResponse
4259 // We send a message to an in-kernel client, and we expect a response, so we compute a
4260 // cookie we can identify the response with.
4261 // If it doesn't understand the notification (it is not power-management savvy)
4262 // we won't wait for it to prepare for sleep. If it tells us via a return code
4263 // in the passed struct that it is currently ready, we won't wait for it to prepare.
4264 // If it tells us via the return code in the struct that it does need time, we will chill.
4265 //*********************************************************************************
4266 void tellClientWithResponse ( OSObject
* object
, void * context
)
4268 struct context
*theContext
= (struct context
*)context
;
4269 IOPowerStateChangeNotification notify
;
4275 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
4276 IOLockLock(theContext
->flags_lock
);
4277 aBool
= OSBoolean::withBoolean(false);
4278 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
4280 IOLockUnlock(theContext
->flags_lock
);
4282 IOPMprot
*pm_vars
= theContext
->us
->pm_vars
;
4283 if (gIOKitDebug
& kIOLogPower
) {
4284 OUR_PMLog(kPMLogClientNotify
, refcon
, (UInt32
) theContext
->msgType
);
4285 if (OSDynamicCast(IOService
, object
)) {
4286 const char *who
= ((IOService
*) object
)->getName();
4287 pm_vars
->thePlatform
->PMLog(who
,
4288 kPMLogClientNotify
, * (UInt32
*) object
, (UInt32
) object
);
4289 } else if (OSDynamicCast(_IOServiceInterestNotifier
, object
)) {
4290 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
4291 OUR_PMLog(kPMLogClientNotify
, (UInt32
) n
->handler
, 0);
4295 notify
.powerRef
= (void *)refcon
;
4296 notify
.returnValue
= 0;
4297 notify
.stateNumber
= theContext
->stateNumber
;
4298 notify
.stateFlags
= theContext
->stateFlags
;
4299 retCode
= theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)¬ify
);
4300 if ( retCode
== kIOReturnSuccess
)
4302 if ( notify
.returnValue
== 0 )
4304 // client doesn't want time to respond
4305 IOLockLock(theContext
->flags_lock
);
4306 aBool
= OSBoolean::withBoolean(true);
4307 // so set its flag true
4308 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
);
4310 IOLockUnlock(theContext
->flags_lock
);
4311 OUR_PMLog(kPMLogClientAcknowledge
, refcon
, (UInt32
) object
);
4313 IOLockLock(theContext
->flags_lock
);
4315 // it does want time, and it hasn't responded yet
4316 theFlag
= theContext
->responseFlags
->getObject(theContext
->counter
);
4319 if ( ((OSBoolean
*)theFlag
)->isFalse() )
4321 // so note its time requirement
4322 if ( theContext
->maxTimeRequested
< notify
.returnValue
)
4324 theContext
->maxTimeRequested
= notify
.returnValue
;
4328 IOLockUnlock(theContext
->flags_lock
);
4331 OUR_PMLog(kPMLogClientAcknowledge
, refcon
, 0);
4332 // not a client of ours
4333 IOLockLock(theContext
->flags_lock
);
4334 // so we won't be waiting for response
4335 aBool
= OSBoolean::withBoolean(true);
4336 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
);
4338 IOLockUnlock(theContext
->flags_lock
);
4340 theContext
->counter
+= 1;
4344 //*********************************************************************************
4347 // Notify registered applications and kernel clients that we are not
4350 // Subclass can override this to send a different message type. Parameter is
4351 // the aborted destination state number.
4352 //*********************************************************************************
4354 void IOService::tellNoChangeDown ( unsigned long )
4356 return tellClients(kIOMessageDeviceWillNotPowerOff
);
4360 //*********************************************************************************
4363 // Notify registered applications and kernel clients that we are raising power.
4365 // Subclass can override this to send a different message type. Parameter is
4366 // the aborted destination state number.
4367 //*********************************************************************************
4369 void IOService::tellChangeUp ( unsigned long )
4371 return tellClients(kIOMessageDeviceHasPoweredOn
);
4375 //*********************************************************************************
4378 // Notify registered applications and kernel clients of something.
4379 //*********************************************************************************
4381 void IOService::tellClients ( int messageType
)
4383 struct context theContext
;
4385 theContext
.msgType
= messageType
;
4386 theContext
.us
= this;
4387 theContext
.stateNumber
= priv
->head_note_state
;
4388 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
4390 applyToInterested(gIOAppPowerStateInterest
,tellClient
,(void *)&theContext
);
4391 applyToInterested(gIOGeneralInterest
,tellClient
,(void *)&theContext
);
4395 //*********************************************************************************
4398 // Notify a registered application or kernel client of something.
4399 //*********************************************************************************
4400 void tellClient ( OSObject
* object
, void * context
)
4402 struct context
*theContext
= (struct context
*)context
;
4403 IOPowerStateChangeNotification notify
;
4405 notify
.powerRef
= (void *) 0;
4406 notify
.returnValue
= 0;
4407 notify
.stateNumber
= theContext
->stateNumber
;
4408 notify
.stateFlags
= theContext
->stateFlags
;
4410 theContext
->us
->messageClient(theContext
->msgType
,object
, ¬ify
);
4414 // **********************************************************************************
4417 // **********************************************************************************
4418 bool IOService::checkForDone ( void )
4423 IOLockLock(priv
->flags_lock
);
4424 if ( pm_vars
->responseFlags
== NULL
)
4426 IOLockUnlock(priv
->flags_lock
);
4430 for ( i
= 0; ; i
++ )
4432 theFlag
= pm_vars
->responseFlags
->getObject(i
);
4433 if ( theFlag
== NULL
)
4437 if ( ((OSBoolean
*)theFlag
)->isFalse() )
4439 IOLockUnlock(priv
->flags_lock
);
4443 IOLockUnlock(priv
->flags_lock
);
4448 // **********************************************************************************
4451 // **********************************************************************************
4452 bool IOService::responseValid ( unsigned long x
)
4454 UInt16 serialComponent
;
4455 UInt16 ordinalComponent
;
4457 unsigned long refcon
= (unsigned long)x
;
4460 serialComponent
= (refcon
>>16) & 0xFFFF;
4461 ordinalComponent
= refcon
& 0xFFFF;
4463 if ( serialComponent
!= pm_vars
->serialNumber
)
4468 IOLockLock(priv
->flags_lock
);
4469 if ( pm_vars
->responseFlags
== NULL
)
4471 IOLockUnlock(priv
->flags_lock
);
4475 theFlag
= pm_vars
->responseFlags
->getObject(ordinalComponent
);
4479 IOLockUnlock(priv
->flags_lock
);
4483 if ( ((OSBoolean
*)theFlag
)->isFalse() )
4485 aBool
= OSBoolean::withBoolean(true);
4486 pm_vars
->responseFlags
->replaceObject(ordinalComponent
,aBool
);
4490 IOLockUnlock(priv
->flags_lock
);
4495 // **********************************************************************************
4498 // Our power state is about to lower, and we have notified applications
4499 // and kernel clients, and one of them has acknowledged. If this is the last to do
4500 // so, and all acknowledgements are positive, we continue with the power change.
4502 // We serialize this processing with timer expiration with a command gate on the
4503 // power management workloop, which the timer expiration is command gated to as well.
4504 // **********************************************************************************
4505 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
4507 if ( ! initialized
)
4510 return kIOReturnSuccess
;
4513 return pm_vars
->PMcommandGate
->runAction(serializedAllowPowerChange
,(void *)refcon
);
4517 IOReturn
serializedAllowPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
4519 return ((IOService
*)owner
)->serializedAllowPowerChange2((unsigned long)refcon
);
4522 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
4525 if ( ! responseValid(refcon
) )
4527 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
4529 return kIOReturnSuccess
;
4531 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientAcknowledge
,refcon
,0);
4533 return allowCancelCommon();
4537 // **********************************************************************************
4538 // cancelPowerChange
4540 // Our power state is about to lower, and we have notified applications
4541 // and kernel clients, and one of them has vetoed the change. If this is the last
4542 // client to respond, we abandon the power change.
4544 // We serialize this processing with timer expiration with a command gate on the
4545 // power management workloop, which the timer expiration is command gated to as well.
4546 // **********************************************************************************
4547 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
4549 if ( ! initialized
)
4552 return kIOReturnSuccess
;
4555 return pm_vars
->PMcommandGate
->runAction(serializedCancelPowerChange
,(void *)refcon
);
4559 IOReturn
serializedCancelPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
4561 return ((IOService
*)owner
)->serializedCancelPowerChange2((unsigned long)refcon
);
4564 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
4567 if ( ! responseValid(refcon
) )
4569 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
4571 return kIOReturnSuccess
;
4573 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientCancel
,refcon
,0);
4575 pm_vars
->doNotPowerDown
= true;
4577 return allowCancelCommon();
4581 // **********************************************************************************
4582 // allowCancelCommon
4584 // **********************************************************************************
4585 IOReturn
IOService::allowCancelCommon ( void )
4587 if (! acquire_lock() )
4589 return kIOReturnSuccess
;
4592 // is this the last response?
4593 if ( checkForDone() )
4595 // yes, stop the timer
4597 IOUnlock(priv
->our_lock
);
4598 IOLockLock(priv
->flags_lock
);
4599 if ( pm_vars
->responseFlags
)
4601 pm_vars
->responseFlags
->release();
4602 pm_vars
->responseFlags
= NULL
;
4604 IOLockUnlock(priv
->flags_lock
);
4605 switch (priv
->machine_state
) {
4606 case kIOPM_OurChangeTellClientsPowerDown
:
4607 // our change, was it vetoed?
4608 if ( ! pm_vars
->doNotPowerDown
)
4610 // no, we can continue
4611 OurChangeTellClientsPowerDown();
4613 // yes, rescind the warning
4614 tellNoChangeDown(priv
->head_note_state
);
4615 // mark the change note un-actioned
4616 priv
->head_note_flags
|= IOPMNotDone
;
4622 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
4623 OurChangeTellPriorityClientsPowerDown();
4625 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
4626 // our change, continue
4627 OurChangeNotifyInterestedDriversWillChange();
4629 case kIOPM_ParentDownTellPriorityClientsPowerDown_Immediate
:
4630 // parent change, continue
4631 ParentDownTellPriorityClientsPowerDown_Delayed();
4633 case kIOPM_ParentDownNotifyInterestedDriversWillChange_Delayed
:
4634 // parent change, continue
4635 ParentDownNotifyInterestedDriversWillChange_Delayed();
4640 IOUnlock(priv
->our_lock
);
4643 return kIOReturnSuccess
;
4648 //*********************************************************************************
4649 // c_PM_clamp_Timer_Expired (C Func)
4651 // Called when our clamp timer expires...we will call the object method.
4652 //*********************************************************************************
4654 static void c_PM_Clamp_Timer_Expired (OSObject
* client
, IOTimerEventSource
*)
4657 ((IOService
*)client
)->PM_Clamp_Timer_Expired ();
4662 //*********************************************************************************
4663 // PM_Clamp_Timer_Expired
4665 // called when clamp timer expires...set power state to 0.
4666 //*********************************************************************************
4668 void IOService::PM_Clamp_Timer_Expired (void)
4671 if ( ! initialized
)
4677 changePowerStateToPriv (0);
4681 //******************************************************************************
4684 // Set to highest available power state for a minimum of duration milliseconds
4685 //******************************************************************************
4687 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
4689 void IOService::clampPowerOn (unsigned long duration
)
4692 changePowerStateToPriv (pm_vars
->theNumberOfPowerStates
-1);
4694 if ( priv
->clampTimerEventSrc
== NULL
) {
4695 priv
->clampTimerEventSrc
= IOTimerEventSource::timerEventSource(this,
4696 c_PM_Clamp_Timer_Expired
);
4698 IOWorkLoop
* workLoop
= getPMworkloop ();
4700 if ( !priv
->clampTimerEventSrc
|| !workLoop
||
4701 ( workLoop
->addEventSource( priv
->clampTimerEventSrc
) != kIOReturnSuccess
) ) {
4706 priv
->clampTimerEventSrc
->setTimeout(300*USEC_PER_SEC
, USEC_PER_SEC
);
4710 //*********************************************************************************
4713 // Does nothing here. This should be implemented in a subclass driver.
4714 //*********************************************************************************
4716 IOReturn
IOService::setPowerState ( unsigned long powerStateOrdinal
, IOService
* whatDevice
)
4722 //*********************************************************************************
4723 // maxCapabilityForDomainState
4725 // Finds the highest power state in the array whose input power
4726 // requirement is equal to the input parameter. Where a more intelligent
4727 // decision is possible, override this in the subclassed driver.
4728 //*********************************************************************************
4730 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
4734 if (pm_vars
->theNumberOfPowerStates
== 0 )
4738 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- )
4740 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
)
4749 //*********************************************************************************
4750 // initialPowerStateForDomainState
4752 // Finds the highest power state in the array whose input power
4753 // requirement is equal to the input parameter. Where a more intelligent
4754 // decision is possible, override this in the subclassed driver.
4755 //*********************************************************************************
4757 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
4761 if (pm_vars
->theNumberOfPowerStates
== 0 )
4765 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- )
4767 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
)
4776 //*********************************************************************************
4777 // powerStateForDomainState
4779 // Finds the highest power state in the array whose input power
4780 // requirement is equal to the input parameter. Where a more intelligent
4781 // decision is possible, override this in the subclassed driver.
4782 //*********************************************************************************
4784 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
4788 if (pm_vars
->theNumberOfPowerStates
== 0 )
4792 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- )
4794 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
)
4803 //*********************************************************************************
4806 // Does nothing here. This should be implemented in a subclass driver.
4807 //*********************************************************************************
4809 bool IOService::didYouWakeSystem ( void )
4815 //*********************************************************************************
4816 // powerStateWillChangeTo
4818 // Does nothing here. This should be implemented in a subclass driver.
4819 //*********************************************************************************
4821 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
4827 //*********************************************************************************
4828 // powerStateDidChangeTo
4830 // Does nothing here. This should be implemented in a subclass driver.
4831 //*********************************************************************************
4833 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
4839 //*********************************************************************************
4842 // Does nothing here. This should be implemented in a subclass policy-maker.
4843 //*********************************************************************************
4845 void IOService::powerChangeDone ( unsigned long )
4850 //*********************************************************************************
4853 // Does nothing here. This should be implemented in a subclass driver.
4854 //*********************************************************************************
4856 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
4864 #define super OSObject
4866 OSDefineMetaClassAndStructors(IOPMprot
, OSObject
)
4867 //*********************************************************************************
4870 // Serialize protected instance variables for debug output.
4871 //*********************************************************************************
4872 bool IOPMprot::serialize(OSSerialize
*s
) const
4874 OSString
* theOSString
;
4881 // estimate how many bytes we need to present all power states
4882 buf_size
= 150 // beginning and end of string
4883 + (275 * (int)theNumberOfPowerStates
) // size per state
4884 + 100; // extra room just for kicks
4886 buffer
= ptr
= IONew(char, buf_size
);
4890 ptr
+= sprintf(ptr
,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates
);
4892 if ( theNumberOfPowerStates
!= 0 ) {
4893 ptr
+= sprintf(ptr
,"version %d, ",(unsigned int)thePowerStates
[0].version
);
4896 if ( theNumberOfPowerStates
!= 0 ) {
4897 for ( i
= 0; i
< (int)theNumberOfPowerStates
; i
++ ) {
4898 ptr
+= sprintf(ptr
, "power state %d = { ",i
);
4899 ptr
+= sprintf(ptr
,"capabilityFlags %08x, ",(unsigned int)thePowerStates
[i
].capabilityFlags
);
4900 ptr
+= sprintf(ptr
,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates
[i
].outputPowerCharacter
);
4901 ptr
+= sprintf(ptr
,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates
[i
].inputPowerRequirement
);
4902 ptr
+= sprintf(ptr
,"staticPower %d, ",(unsigned int)thePowerStates
[i
].staticPower
);
4903 ptr
+= sprintf(ptr
,"unbudgetedPower %d, ",(unsigned int)thePowerStates
[i
].unbudgetedPower
);
4904 ptr
+= sprintf(ptr
,"powerToAttain %d, ",(unsigned int)thePowerStates
[i
].powerToAttain
);
4905 ptr
+= sprintf(ptr
,"timeToAttain %d, ",(unsigned int)thePowerStates
[i
].timeToAttain
);
4906 ptr
+= sprintf(ptr
,"settleUpTime %d, ",(unsigned int)thePowerStates
[i
].settleUpTime
);
4907 ptr
+= sprintf(ptr
,"timeToLower %d, ",(unsigned int)thePowerStates
[i
].timeToLower
);
4908 ptr
+= sprintf(ptr
,"settleDownTime %d, ",(unsigned int)thePowerStates
[i
].settleDownTime
);
4909 ptr
+= sprintf(ptr
,"powerDomainBudget %d }, ",(unsigned int)thePowerStates
[i
].powerDomainBudget
);
4913 ptr
+= sprintf(ptr
,"aggressiveness = %d, ",(unsigned int)aggressiveness
);
4914 ptr
+= sprintf(ptr
,"myCurrentState = %d, ",(unsigned int)myCurrentState
);
4915 ptr
+= sprintf(ptr
,"parentsCurrentPowerFlags = %08x, ",(unsigned int)parentsCurrentPowerFlags
);
4916 ptr
+= sprintf(ptr
,"maxCapability = %d }",(unsigned int)maxCapability
);
4918 theOSString
= OSString::withCString(buffer
);
4919 rtn_code
= theOSString
->serialize(s
);
4920 theOSString
->release();
4921 IODelete(buffer
, char, buf_size
);
4928 #define super OSObject
4930 OSDefineMetaClassAndStructors(IOPMpriv
, OSObject
)
4931 //*********************************************************************************
4934 // Serialize private instance variables for debug output.
4935 //*********************************************************************************
4936 bool IOPMpriv::serialize(OSSerialize
*s
) const
4938 OSString
* theOSString
;
4942 IOPMinformee
* nextObject
;
4944 buffer
= ptr
= IONew(char, 2000);
4948 ptr
+= sprintf(ptr
,"{ this object = %08x",(unsigned int)owner
);
4949 if ( we_are_root
) {
4950 ptr
+= sprintf(ptr
," (root)");
4952 ptr
+= sprintf(ptr
,", ");
4954 nextObject
= interestedDrivers
->firstInList(); // display interested drivers
4955 while ( nextObject
!= NULL
) {
4956 ptr
+= sprintf(ptr
,"interested driver = %08x, ",(unsigned int)nextObject
->whatObject
);
4957 nextObject
= interestedDrivers
->nextInList(nextObject
);
4960 if ( machine_state
!= kIOPM_Finished
) {
4961 ptr
+= sprintf(ptr
,"machine_state = %d, ",(unsigned int)machine_state
);
4962 ptr
+= sprintf(ptr
,"driver_timer = %d, ",(unsigned int)driver_timer
);
4963 ptr
+= sprintf(ptr
,"settle_time = %d, ",(unsigned int)settle_time
);
4964 ptr
+= sprintf(ptr
,"head_note_flags = %08x, ",(unsigned int)head_note_flags
);
4965 ptr
+= sprintf(ptr
,"head_note_state = %d, ",(unsigned int)head_note_state
);
4966 ptr
+= sprintf(ptr
,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags
);
4967 ptr
+= sprintf(ptr
,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState
);
4968 ptr
+= sprintf(ptr
,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags
);
4969 ptr
+= sprintf(ptr
,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks
);
4972 if ( device_overrides
) {
4973 ptr
+= sprintf(ptr
,"device overrides, ");
4975 ptr
+= sprintf(ptr
,"driverDesire = %d, ",(unsigned int)driverDesire
);
4976 ptr
+= sprintf(ptr
,"deviceDesire = %d, ",(unsigned int)deviceDesire
);
4977 ptr
+= sprintf(ptr
,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState
);
4978 ptr
+= sprintf(ptr
,"previousRequest = %d }",(unsigned int)previousRequest
);
4980 theOSString
= OSString::withCString(buffer
);
4981 rtn_code
= theOSString
->serialize(s
);
4982 theOSString
->release();
4983 IODelete(buffer
, char, 2000);