2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include <IOKit/IOService.h>
24 #include <IOKit/IOLib.h>
25 #include <IOKit/IOCommandGate.h>
26 #include <IOKit/IOTimerEventSource.h>
27 #include <IOKit/IOWorkLoop.h>
28 #include <IOKit/IOPlatformExpert.h>
29 #include <IOKit/assert.h>
30 #include <IOKit/IOMessage.h>
31 #include <IOKit/IOKitDebug.h>
32 #include <IOKit/IOTimeStamp.h>
33 #include <IOKit/pwr_mgt/IOPMinformee.h>
34 #include "IOKit/pwr_mgt/IOPMinformeeList.h"
35 #include "IOKit/pwr_mgt/IOPMchangeNoteList.h"
36 #include "IOKit/pwr_mgt/IOPMlog.h"
37 #include "IOKit/pwr_mgt/IOPowerConnection.h"
38 #include <kern/clock.h>
40 #define super IORegistryEntry
42 // Some debug functions
44 ioSPMTrace(unsigned int csc
,
45 unsigned int a
= 0, unsigned int b
= 0,
46 unsigned int c
= 0, unsigned int d
= 0)
48 if (gIOKitDebug
& kIOLogTracePower
)
49 IOTimeStampConstant(IODBG_POWER(csc
), a
, b
, c
, d
);
53 ioSPMTraceStart(unsigned int csc
,
54 unsigned int a
= 0, unsigned int b
= 0,
55 unsigned int c
= 0, unsigned int d
= 0)
57 if (gIOKitDebug
& kIOLogTracePower
)
58 IOTimeStampConstant(IODBG_POWER(csc
)|DBG_FUNC_START
, a
, b
, c
, d
);
62 ioSPMTraceEnd(unsigned int csc
,
63 unsigned int a
= 0, unsigned int b
= 0,
64 unsigned int c
= 0, unsigned int d
= 0)
66 if (gIOKitDebug
& kIOLogTracePower
)
67 IOTimeStampConstant(IODBG_POWER(csc
)|DBG_FUNC_END
, a
, b
, c
, d
);
71 static void ack_timer_expired(thread_call_param_t
);
72 static void settle_timer_expired(thread_call_param_t
);
73 IOReturn
unIdleDevice ( OSObject
*, void *, void *, void *, void * );
74 static void PM_idle_timer_expired(OSObject
*, IOTimerEventSource
*);
75 static void c_PM_Clamp_Timer_Expired (OSObject
* client
,IOTimerEventSource
*);
76 void tellAppWithResponse ( OSObject
* object
, void * context
);
77 void tellClientWithResponse ( OSObject
* object
, void * context
);
78 void tellClient ( OSObject
* object
, void * context
);
79 IOReturn
serializedAllowPowerChange ( OSObject
*, void *, void *, void *, void *);
80 IOReturn
serializedCancelPowerChange ( OSObject
*, void *, void *, void *, void *);
82 extern const IORegistryPlane
* gIOPowerPlane
;
85 // and there's 1000 nanoseconds in a microsecond:
86 #define ns_per_us 1000
89 // The current change note is processed by a state machine.
90 // Inputs are acks from interested parties, ack from the controlling driver,
91 // ack timeouts, settle timeout, and powerStateDidChange from the parent.
92 // These are the states:
95 IOPMour_prechange_03
= 1,
117 enum { // values of outofbandparameter
122 struct context
{ // used for applyToInterested
123 OSArray
* responseFlags
;
126 UInt32 maxTimeRequested
;
130 unsigned long stateNumber
;
131 IOPMPowerFlags stateFlags
;
134 // five minutes in microseconds
135 #define FIVE_MINUTES 5*60*1000000
136 #define k30seconds 30*1000000
139 There are two different kinds of power state changes. One is initiated by a subclassed device object which has either
140 decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
141 idle device and has asked it to become usable. The second kind of power state change is initiated by the power
142 domain parent. The two are handled slightly differently.
144 There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when
145 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
146 at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower
147 power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the
148 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
149 wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet,
150 so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire
151 power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
154 This is how a power change initiated by the subclass device is handled:
155 First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't
156 acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our
157 acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to
158 the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify
159 interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done.
160 If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
161 it lower the power domain state.
163 This is how a change to a lower power domain state initiated by the parent is handled:
164 First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are
165 notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume
166 that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested
167 parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify
168 our interested parties that the power state has changed, and when they have all acknowledged, we're done.
170 This is how a change to a higher power domain state initiated by the parent is handled:
171 We figure out what power state we will be in when the new domain state is reached. If it is different from our current
172 state we acknowledge the parent. When all the parent's interested parties have acknowledged, it raises power in the
173 domain and waits for power to settle. Then it notifies everyone that the new state has been reached. When we get this call,
174 we call the controlling driver, instructing it to assume the new state, and wait for power to settle. Then we notify our interested
175 parties. When they all acknowledge we are done.
177 In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples:
178 A change to a lower domain state may not affect us because we are already in a low enough state, and
179 We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
180 In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange
181 method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
182 When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
184 Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
185 four major paths through the state machine:
187 The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state.
188 The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent.
189 When the parent calls powerStateDidChange, we acknowledge the parent again, and we're done.
191 The first is fairly simple. It starts when a power domain child calls requestPowerDomainState and we decide to change power states
192 to accomodate the child, or if our power-controlling driver calls changePowerStateTo, or if some other driver which is using our
193 device calls makeUsable, or if a subclassed object calls changePowerStateToPriv. These are all power changes initiated by us, not
194 forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go
195 on to state "our_prechange_1". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
196 acknowledgePowerChange. We move on to state "our_prechange_1" when all the stragglers have acknowledged,
197 or when the ack timer expires on all those which didn't acknowledge. In "our_prechange_1" we call the power-controlling
198 driver to change the power state of the hardware. If it returns saying it has done so, we go on to state "our_prechange_2".
199 Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the
200 ack timer expires, we go on. In "our_prechange_2", we look in the power state array to see if there is any settle time required
201 when changing from our current state to the new state. If not, we go right away to "our_prechange_3". Otherwise, we
202 set the settle timer and wait. When it expires, we move on. In "our_prechange_3" state, we notify all our interested parties
203 via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return
204 code, we move on to "our_prechange_4". Otherwise we set the ack timer and wait. When they have all acknowledged, or
205 when the ack timer has expired for those that didn't, we move on to "our_prechange_4", where we remove the used
206 change note from the head of the queue and start the next one if one exists.
208 Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled
209 differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification
210 in two different ways, so each of the parent paths is really two.
212 When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
213 what state that will put our device in. Then we embark on the state machine path "IOPMparent_down_1"
214 and "IOPMparent_down_2", in which we notify interested parties of the upcoming change, instruct our driver to make
215 the change, check for settle time, and notify interested parties of the completed change. If we get to the end of this path without
216 stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
217 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.
218 If we do stall in any of those states, we return IOPMWillAckLater to the parent and enter the parallel path "IOPMparent_down_4"
219 "IOPMparent_down_5", and "IOPMparent_down_3", where we continue with the same processing, except that at the end we
220 acknowledge the parent explicitly via acknowledgePowerChange, and we're done with the change.
221 Then when the parent calls us at powerStateDidChange we acknowledging via return code, because we have already made
222 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.
224 The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
225 that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
226 the parent. This case is different, though in that our device changes state in the second half, after the parent calls
227 powerStateDidChange rather than before, as in the power-lowering case.
229 When the parent calls our powerDomainWillChange method, notifying us that it will raise power in the domain, we acknowledge
230 via return code, because there's really nothing we can do until the power is actually raised in the domain.
231 When the parent calls us at powerStateDidChange, we start by notifying our interested parties. If they all acknowledge via return code,
232 we go on to" IOPMparent_up_1" to instruct the driver to raise its power level. After that, we check for any
233 necessary settling time in "IOPMparent_up_2", and we notify all interested parties that power has changed
234 in "IOPMparent_up_3". If none of these operations stall, we acknowledge the parent via return code, release
235 the change note, and start the next, if there is one. If one of them does stall, we enter the parallel path "IOPMparent_up_0",
236 "IOPMparent_up_4", "IOPMparent_up_5", and "IOPMparent_up_6", which ends with
237 our explicit acknowledgement to the parent.
242 const char priv_key
[ ] = "Power Management private data";
243 const char prot_key
[ ] = "Power Management protected data";
246 void IOService::PMinit ( void )
248 if ( ! initialized
) {
250 pm_vars
= new IOPMprot
; // make space for our variables
255 setProperty(prot_key
, (OSObject
*) pm_vars
); // add these to the properties
256 setProperty(priv_key
, (OSObject
*) priv
);
259 pm_vars
->theNumberOfPowerStates
= 0; // then initialize them
260 priv
->we_are_root
= false;
261 pm_vars
->theControllingDriver
= NULL
;
262 priv
->our_lock
= IOLockAlloc();
263 priv
->flags_lock
= IOLockAlloc();
264 priv
->queue_lock
= IOLockAlloc();
265 pm_vars
->childLock
= IOLockAlloc();
266 pm_vars
->parentLock
= IOLockAlloc();
267 priv
->interestedDrivers
= new IOPMinformeeList
;
268 priv
->interestedDrivers
->initialize();
269 priv
->changeList
= new IOPMchangeNoteList
;
270 priv
->changeList
->initialize();
271 pm_vars
->aggressiveness
= 0;
272 for (unsigned int i
= 0; i
<= kMaxType
; i
++) {
273 pm_vars
->current_aggressiveness_values
[i
] = 0;
274 pm_vars
->current_aggressiveness_valid
[i
] = false;
276 pm_vars
->myCurrentState
= 0;
277 priv
->imminentState
= 0;
278 priv
->ourDesiredPowerState
= 0;
279 pm_vars
->parentsCurrentPowerFlags
= 0;
280 pm_vars
->maxCapability
= 0;
281 priv
->driverDesire
= 0;
282 priv
->deviceDesire
= 0;
283 priv
->initial_change
= true;
284 priv
->need_to_become_usable
= false;
285 priv
->previousRequest
= 0;
286 priv
->device_overrides
= false;
287 priv
->machine_state
= IOPMfinished
;
288 priv
->timerEventSrc
= NULL
;
289 priv
->clampTimerEventSrc
= NULL
;
290 pm_vars
->PMworkloop
= NULL
;
291 priv
->activityLock
= NULL
;
292 pm_vars
->ourName
= getName();
293 pm_vars
->thePlatform
= getPlatform();
294 pm_vars
->parentsKnowState
= false;
295 assert( pm_vars
->thePlatform
!= 0 );
296 priv
->clampOn
= false;
297 pm_vars
->serialNumber
= 0;
298 pm_vars
->responseFlags
= NULL
;
299 pm_vars
->doNotPowerDown
= true;
300 pm_vars
->PMcommandGate
= NULL
;
301 priv
->ackTimer
= thread_call_allocate((thread_call_func_t
)ack_timer_expired
, (thread_call_param_t
)this);
302 priv
->settleTimer
= thread_call_allocate((thread_call_func_t
)settle_timer_expired
, (thread_call_param_t
)this);
308 //*********************************************************************************
311 // Free up the data created in PMinit, if it exists.
312 //*********************************************************************************
313 void IOService::PMfree ( void )
316 if ( priv
->clampTimerEventSrc
!= NULL
) {
317 getPMworkloop()->removeEventSource(priv
->clampTimerEventSrc
);
318 priv
->clampTimerEventSrc
->release();
319 priv
->clampTimerEventSrc
= NULL
;
321 if ( priv
->timerEventSrc
!= NULL
) {
322 pm_vars
->PMworkloop
->removeEventSource(priv
->timerEventSrc
);
323 priv
->timerEventSrc
->release();
324 priv
->timerEventSrc
= NULL
;
326 if ( priv
->settleTimer
) {
327 thread_call_cancel(priv
->settleTimer
);
328 thread_call_free(priv
->settleTimer
);
329 priv
->settleTimer
= NULL
;
331 if ( priv
->ackTimer
) {
332 thread_call_cancel(priv
->ackTimer
);
333 thread_call_free(priv
->ackTimer
);
334 priv
->ackTimer
= NULL
;
336 if ( priv
->our_lock
) {
337 IOLockFree(priv
->our_lock
);
338 priv
->our_lock
= NULL
;
340 if ( priv
->flags_lock
) {
341 IOLockFree(priv
->flags_lock
);
342 priv
->flags_lock
= NULL
;
344 if ( priv
->activityLock
) {
345 IOLockFree(priv
->activityLock
);
346 priv
->activityLock
= NULL
;
348 priv
->interestedDrivers
->release();
349 priv
->changeList
->release();
350 priv
->release(); // remove instance variables
354 if ( pm_vars
->PMcommandGate
) {
355 pm_vars
->PMcommandGate
->release();
356 pm_vars
->PMcommandGate
= NULL
;
358 if ( pm_vars
->PMworkloop
) {
359 // The work loop object returned from getPMworkLoop() is
360 // never retained, therefore it should not be released.
361 // pm_vars->PMworkloop->release();
362 pm_vars
->PMworkloop
= NULL
;
364 if ( pm_vars
->responseFlags
) {
365 pm_vars
->responseFlags
->release();
366 pm_vars
->responseFlags
= NULL
;
368 pm_vars
->release(); // remove instance variables
373 //*********************************************************************************
376 // Disconnect the node from its parents and children in the Power Plane.
377 //*********************************************************************************
378 void IOService::PMstop ( void )
382 IOPowerConnection
* connection
;
383 IOService
* theChild
;
384 IOService
* theParent
;
386 removeProperty(prot_key
); // remove the properties
387 removeProperty(priv_key
);
389 iter
= getParentIterator(gIOPowerPlane
); // detach parents
392 while ( (next
= iter
->getNextObject()) ) {
393 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
394 theParent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
396 theParent
->removePowerChild(connection
);
397 theParent
->release();
403 detachAbove( gIOPowerPlane
); // detach IOConnections
405 pm_vars
->parentsKnowState
= false; // no more power state changes
407 iter
= getChildIterator(gIOPowerPlane
); // detach children
410 while ( (next
= iter
->getNextObject()) ) {
411 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
412 theChild
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
414 connection
->detachFromChild(theChild
,gIOPowerPlane
); // detach nub from child
417 detachFromChild(connection
,gIOPowerPlane
); // detach us from nub
423 // Remove all interested drivers from the list, including the power
424 // controlling driver.
426 // Usually, the controlling driver and the policy-maker functionality
427 // are implemented by the same object, and without the deregistration,
428 // the object will be holding an extra retain on itself, and cannot
431 if ( priv
&& priv
->interestedDrivers
)
433 IOPMinformee
* informee
;
435 while (( informee
= priv
->interestedDrivers
->firstInList() ))
436 deRegisterInterestedDriver( informee
->whatObject
);
441 //*********************************************************************************
444 // A policy-maker calls its nub here when initializing, to be attached into
445 // the power management hierarchy. The default function is to call the
446 // platform expert, which knows how to do it. This method is overridden
447 // by a nub subclass which may either know how to do it, or may need
448 // to take other action.
450 // This may be the only "power management" method used in a nub,
451 // meaning it may not be initialized for power management.
452 //*********************************************************************************
453 void IOService::joinPMtree ( IOService
* driver
)
455 IOPlatformExpert
* thePlatform
;
457 thePlatform
= getPlatform();
458 assert(thePlatform
!= 0 );
459 thePlatform
->PMRegisterDevice(this,driver
);
463 //*********************************************************************************
466 // Power Managment is informing us that we are the root power domain.
467 // The only difference between us and any other power domain is that
468 // we have no parent and therefore never call it.
469 //*********************************************************************************
470 IOReturn
IOService::youAreRoot ( void )
472 priv
-> we_are_root
= true;
473 pm_vars
->parentsKnowState
= true;
474 attachToParent( getRegistryRoot(),gIOPowerPlane
);
480 //*********************************************************************************
483 // Power Management is informing us who our parent is.
484 // If we have a controlling driver, find out, given our newly-informed
485 // power domain state, what state it would be in, and then tell it
486 // to assume that state.
487 //*********************************************************************************
488 IOReturn
IOService::setPowerParent ( IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags currentState
)
492 IOPowerConnection
* connection
;
493 unsigned long tempDesire
;
495 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetParent
,stateKnown
,currentState
);
497 IOLockLock(pm_vars
->parentLock
);
499 if ( stateKnown
&& ((pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
)) ) {
500 getPMworkloop(); // we have a path to the root
501 if ( pm_vars
->PMworkloop
!= NULL
) { // find out the workloop
502 if ( pm_vars
->PMcommandGate
== NULL
) { // and make our command gate
503 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
504 if ( pm_vars
->PMcommandGate
!= NULL
) {
505 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
511 IOLockUnlock(pm_vars
->parentLock
);
513 theParent
->setParentCurrentPowerFlags(currentState
); // set our connection data
514 theParent
->setParentKnowsState(stateKnown
);
516 pm_vars
->parentsKnowState
= true; // combine parent knowledge
517 pm_vars
->parentsCurrentPowerFlags
= 0;
519 iter
= getParentIterator(gIOPowerPlane
);
522 while ( (next
= iter
->getNextObject()) ) {
523 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
524 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
525 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
531 if ( (pm_vars
->theControllingDriver
!= NULL
) &&
532 (pm_vars
->parentsKnowState
) ) {
533 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
534 tempDesire
= priv
->deviceDesire
; // initially change into the state we are already in
535 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
536 computeDesiredState();
537 priv
->previousRequest
= 0xffffffff;
539 priv
->deviceDesire
= tempDesire
; // put this back like before
546 //*********************************************************************************
549 // Power Management is informing us who our children are.
550 //*********************************************************************************
551 IOReturn
IOService::addPowerChild ( IOService
* theChild
)
553 IOPowerConnection
* connection
;
556 if ( ! initialized
) {
557 return IOPMNotYetInitialized
; // we're not a power-managed IOService
560 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAddChild
,0,0);
562 connection
= new IOPowerConnection
; // make a nub
565 connection
->start(this);
566 connection
->setAwaitingAck(false);
568 attachToChild( connection
,gIOPowerPlane
); // connect it up
569 connection
->attachToChild( theChild
,gIOPowerPlane
);
570 connection
->release();
572 if ( (pm_vars
->theControllingDriver
== NULL
) || // tell it the current state of the power domain
573 ! (inPlane(gIOPowerPlane
)) ||
574 ! (pm_vars
->parentsKnowState
) ) {
575 theChild
->setPowerParent(connection
,false,0);
576 if ( inPlane(gIOPowerPlane
) ) {
577 for (i
= 0; i
<= kMaxType
; i
++) {
578 if ( pm_vars
->current_aggressiveness_valid
[i
] ) {
579 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
585 theChild
->setPowerParent(connection
,true,pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].outputPowerCharacter
);
586 for (i
= 0; i
<= kMaxType
; i
++) {
587 if ( pm_vars
->current_aggressiveness_valid
[i
] ) {
588 theChild
->setAggressiveness (i
, pm_vars
->current_aggressiveness_values
[i
]);
591 add_child_to_active_change(connection
); // catch it up if change is in progress
598 //*********************************************************************************
601 //*********************************************************************************
602 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theNub
)
604 IORegistryEntry
* theChild
;
606 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveChild
,0,0);
610 theChild
= theNub
->copyChildEntry(gIOPowerPlane
); // detach nub from child
612 theNub
->detachFromChild(theChild
, gIOPowerPlane
);
615 detachFromChild(theNub
,gIOPowerPlane
); // detach from the nub
617 if ( theNub
->getAwaitingAck() ) { // are we awaiting an ack from this child?
618 theNub
->setAwaitingAck(false); // yes, pretend we got one
619 if ( acquire_lock() ) {
620 if (priv
->head_note_pendingAcks
!= 0 ) {
621 priv
->head_note_pendingAcks
-= 1; // that's one fewer ack to worry about
622 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
623 stop_ack_timer(); // yes, stop the timer
624 IOUnlock(priv
->our_lock
);
625 all_acked(); // and now we can continue our power change
628 IOUnlock(priv
->our_lock
);
632 IOUnlock(priv
->our_lock
);
639 if ( (pm_vars
->theControllingDriver
== NULL
) || // if not fully initialized
640 ! (inPlane(gIOPowerPlane
)) ||
641 ! (pm_vars
->parentsKnowState
) ) {
642 return IOPMNoErr
; // we can do no more
645 // Perhaps the departing child was holding up idle or system sleep - we need to re-evaluate our
646 // childrens' requests. Clear and re-calculate our kIOPMChildClamp and kIOPMChildClamp2 bits.
647 rebuildChildClampBits();
649 computeDesiredState(); // this may be different now
650 changeState(); // change state if we can now tolerate lower power
656 //*********************************************************************************
657 // registerPowerDriver
659 // A driver has called us volunteering to control power to our device.
660 // If the power state array it provides is richer than the one we already
661 // know about (supplied by an earlier volunteer), then accept the offer.
662 // Notify all interested parties of our power state, which we now know.
663 //*********************************************************************************
665 IOReturn
IOService::registerPowerDriver ( IOService
* controllingDriver
, IOPMPowerState
* powerStates
, unsigned long numberOfStates
)
668 unsigned long tempDesire
;
670 if ( (numberOfStates
> pm_vars
->theNumberOfPowerStates
) && (numberOfStates
> 1) ) {
671 if ( priv
->changeList
->currentChange() == -1 ) {
672 if ( controllingDriver
!= NULL
) {
673 if ( numberOfStates
<= IOPMMaxPowerStates
) {
674 switch ( powerStates
[0].version
) {
676 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
677 (unsigned long)numberOfStates
, (unsigned long)powerStates
[0].version
);
678 for ( i
= 0; i
< numberOfStates
; i
++ ) {
679 pm_vars
->thePowerStates
[i
] = powerStates
[i
];
683 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriver
,
684 (unsigned long) numberOfStates
,(unsigned long) powerStates
[0].version
);
685 for ( i
= 0; i
< numberOfStates
; i
++ ) {
686 pm_vars
->thePowerStates
[i
].version
= powerStates
[i
].version
;
687 pm_vars
->thePowerStates
[i
].capabilityFlags
= powerStates
[i
].capabilityFlags
;
688 pm_vars
->thePowerStates
[i
].outputPowerCharacter
= powerStates
[i
].outputPowerCharacter
;
689 pm_vars
->thePowerStates
[i
].inputPowerRequirement
= powerStates
[i
].inputPowerRequirement
;
690 pm_vars
->thePowerStates
[i
].staticPower
= powerStates
[i
].staticPower
;
691 pm_vars
->thePowerStates
[i
].unbudgetedPower
= powerStates
[i
].unbudgetedPower
;
692 pm_vars
->thePowerStates
[i
].powerToAttain
= powerStates
[i
].powerToAttain
;
693 pm_vars
->thePowerStates
[i
].timeToAttain
= powerStates
[i
].timeToAttain
;
694 pm_vars
->thePowerStates
[i
].settleUpTime
= powerStates
[i
].settleUpTime
;
695 pm_vars
->thePowerStates
[i
].timeToLower
= powerStates
[i
].timeToLower
;
696 pm_vars
->thePowerStates
[i
].settleDownTime
= powerStates
[i
].settleDownTime
;
697 pm_vars
->thePowerStates
[i
].powerDomainBudget
= powerStates
[i
].powerDomainBudget
;
701 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr1
,
702 (unsigned long)powerStates
[0].version
,0);
706 pm_vars
->myCharacterFlags
= 0; // make a mask of all the character bits we know about
707 for ( i
= 0; i
< numberOfStates
; i
++ ) {
708 pm_vars
->myCharacterFlags
|= pm_vars
->thePowerStates
[i
].outputPowerCharacter
;
711 pm_vars
->theNumberOfPowerStates
= numberOfStates
;
712 pm_vars
->theControllingDriver
= controllingDriver
;
713 if ( priv
->interestedDrivers
->findItem(controllingDriver
) == NULL
) { // register it as interested
714 registerInterestedDriver (controllingDriver
); // unless already done
716 if ( priv
->need_to_become_usable
) {
717 priv
->need_to_become_usable
= false;
718 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
721 if ( inPlane(gIOPowerPlane
) &&
722 (pm_vars
->parentsKnowState
) ) {
723 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
724 tempDesire
= priv
->deviceDesire
; // initially change into the state we are already in
725 priv
->deviceDesire
= pm_vars
->theControllingDriver
->initialPowerStateForDomainState(pm_vars
->parentsCurrentPowerFlags
);
726 computeDesiredState();
728 priv
->deviceDesire
= tempDesire
; // put this back like before
732 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr2
,(unsigned long)numberOfStates
,0);
736 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr4
,0,0);
741 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogControllingDriverErr5
,(unsigned long)numberOfStates
,0);
746 //*********************************************************************************
747 // registerInterestedDriver
749 // Add the caller to our list of interested drivers and return our current
750 // power state. If we don't have a power-controlling driver yet, we will
751 // call this interested driver again later when we do get a driver and find
752 // out what the current power state of the device is.
753 //*********************************************************************************
755 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* theDriver
)
757 IOPMinformee
* newInformee
;
758 IOPMPowerFlags futureCapability
;
760 if (theDriver
== NULL
) {
764 newInformee
= new IOPMinformee
; // make new driver node
765 newInformee
->initialize(theDriver
);
766 priv
->interestedDrivers
->addToList(newInformee
); // add it to list of drivers
768 if ( (pm_vars
->theControllingDriver
== NULL
) ||
769 ! (inPlane(gIOPowerPlane
)) ||
770 ! (pm_vars
->parentsKnowState
) ) {
771 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,IOPMNotPowerManaged
,0);
772 return IOPMNotPowerManaged
; // can't tell it a state yet
775 switch (priv
->machine_state
) { // can we notify new driver of a change in progress?
776 case IOPMour_prechange_1
:
777 case IOPMour_prechange_4
:
778 case IOPMparent_down_4
:
779 case IOPMparent_down_6
:
780 case IOPMparent_up_0
:
781 case IOPMparent_up_6
:
782 futureCapability
= priv
->head_note_capabilityFlags
; // yes, remember what we tell it
783 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,(unsigned long)futureCapability
,1);
784 add_driver_to_active_change(newInformee
); // notify it
785 return futureCapability
; // and return the same thing
788 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInterestedDriver
,
789 (unsigned long) pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
,2);
790 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
; // no, return current capability
794 //*********************************************************************************
795 // deRegisterInterestedDriver
797 //*********************************************************************************
798 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* theDriver
)
800 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRemoveDriver
,0,0);
802 priv
->interestedDrivers
->removeFromList(theDriver
); // remove the departing driver
808 //*********************************************************************************
809 // acknowledgePowerChange
811 // After we notified one of the interested drivers or a power-domain child
812 // of an impending change in power, it has called to say it is now
813 // prepared for the change. If this object is the last to
814 // acknowledge this change, we take whatever action we have been waiting
816 // That may include acknowledging to our parent. In this case, we do it
817 // last of all to insure that this doesn't cause the parent to call us some-
818 // where else and alter data we are relying on here (like the very existance
819 // of a "current change note".)
820 //*********************************************************************************
822 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
824 IOPMinformee
* ackingObject
;
825 unsigned long childPower
= kIOPMUnknown
;
826 IOService
* theChild
;
828 ackingObject
= priv
->interestedDrivers
->findItem(whichObject
); // one of our interested drivers?
829 if ( ackingObject
== NULL
) {
830 if ( ! isChild(whichObject
,gIOPowerPlane
) ) {
831 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr1
,0,0);
832 kprintf("errant driver: %s\n",whichObject
->getName());
833 return IOPMNoErr
; // no, just return
836 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChildAcknowledge
,priv
->head_note_pendingAcks
,0);
840 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledge
,priv
->head_note_pendingAcks
,0);
843 if (! acquire_lock() ) {
847 if (priv
->head_note_pendingAcks
!= 0 ) { // yes, make sure we're expecting acks
848 if ( ackingObject
!= NULL
) { // it's an interested driver
849 if ( ackingObject
->timer
!= 0 ) { // make sure we're expecting this ack
850 ackingObject
->timer
= 0; // mark it acked
851 priv
->head_note_pendingAcks
-= 1; // that's one fewer to worry about
852 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
853 stop_ack_timer(); // yes, stop the timer
854 IOUnlock(priv
->our_lock
);
855 all_acked(); // and now we can continue
860 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr2
,0,0); // this driver has already acked
861 kprintf("errant driver: %s\n",whichObject
->getName());
864 else { // it's a child
865 if ( ((IOPowerConnection
*)whichObject
)->getAwaitingAck() ) { // make sure we're expecting this ack
866 priv
->head_note_pendingAcks
-= 1; // that's one fewer to worry about
867 ((IOPowerConnection
*)whichObject
)->setAwaitingAck(false);
868 theChild
= (IOService
*)whichObject
->copyChildEntry(gIOPowerPlane
);
870 childPower
= theChild
->currentPowerConsumption();
873 if ( childPower
== kIOPMUnknown
) {
874 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
877 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
) {
878 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
881 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
882 stop_ack_timer(); // yes, stop the timer
883 IOUnlock(priv
->our_lock
);
884 all_acked(); // and now we can continue
891 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr3
,0,0); // not expecting anybody to ack
892 kprintf("errant driver: %s\n",whichObject
->getName());
894 IOUnlock(priv
->our_lock
);
898 //*********************************************************************************
899 // acknowledgeSetPowerState
901 // After we instructed our controlling driver to change power states,
902 // it has called to say it has finished doing so.
903 // We continue to process the power state change.
904 //*********************************************************************************
906 IOReturn
IOService::acknowledgeSetPowerState ( void )
908 if (! acquire_lock() ) {
912 ioSPMTrace(IOPOWER_ACK
, * (int *) this);
914 if ( priv
->driver_timer
== -1 ) {
915 priv
->driver_timer
= 0; // driver is acking instead of using return code
918 if ( priv
->driver_timer
> 0 ) { // are we expecting this?
919 stop_ack_timer(); // yes, stop the timer
920 priv
->driver_timer
= 0;
921 IOUnlock(priv
->our_lock
);
922 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDriverAcknowledgeSet
,0,0);
927 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr4
,0,0); // no
930 IOUnlock(priv
->our_lock
);
935 //*********************************************************************************
938 // Either the controlling driver has called acknowledgeSetPowerState
939 // or the acknowledgement timer has expired while waiting for that.
940 // We carry on processing the current change note.
941 //*********************************************************************************
943 void IOService::driver_acked ( void )
945 switch (priv
->machine_state
) {
946 case IOPMour_prechange_2
:
949 case IOPMparent_down_5
:
952 case IOPMparent_up_4
:
959 //*********************************************************************************
960 // powerDomainWillChangeTo
962 // Called by the power-hierarchy parent notifying of a new power state
963 // in the power domain.
964 // We enqueue a parent power-change to our queue of power changes.
965 // This may or may not cause us to change power, depending on what
966 // kind of change is occuring in the domain.
967 //*********************************************************************************
969 IOReturn
IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
973 IOPowerConnection
* connection
;
974 unsigned long newStateNumber
;
975 IOPMPowerFlags combinedPowerFlags
;
977 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogWillChange
,(unsigned long)newPowerStateFlags
,0);
979 if ( ! inPlane(gIOPowerPlane
) ) {
980 return IOPMAckImplied
; // somebody goofed
983 IOLockLock(pm_vars
->parentLock
);
985 if ( (pm_vars
->PMworkloop
== NULL
) || (pm_vars
->PMcommandGate
== NULL
) ) {
986 getPMworkloop(); // we have a path to the root,
987 if ( pm_vars
->PMworkloop
!= NULL
) { // so find out the workloop
988 if ( pm_vars
->PMcommandGate
== NULL
) { // and make our command gate
989 pm_vars
->PMcommandGate
= IOCommandGate::commandGate((OSObject
*)this);
990 if ( pm_vars
->PMcommandGate
!= NULL
) {
991 pm_vars
->PMworkloop
->addEventSource(pm_vars
->PMcommandGate
);
997 IOLockUnlock(pm_vars
->parentLock
);
999 combinedPowerFlags
= 0; // combine parents' power states
1001 iter
= getParentIterator(gIOPowerPlane
);
1004 while ( (next
= iter
->getNextObject()) ) {
1005 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1006 if ( connection
== whichParent
){
1007 combinedPowerFlags
|= newPowerStateFlags
;
1010 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
1017 if ( pm_vars
->theControllingDriver
== NULL
) { // we can't take any more action
1018 return IOPMAckImplied
;
1020 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(combinedPowerFlags
);
1021 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainWillChange
,
1022 newStateNumber
,combinedPowerFlags
,whichParent
,newPowerStateFlags
); //make the change
1026 //*********************************************************************************
1027 // powerDomainDidChangeTo
1029 // Called by the power-hierarchy parent after the power state of the power domain
1030 // has settled at a new level.
1031 // We enqueue a parent power-change to our queue of power changes.
1032 // This may or may not cause us to change power, depending on what
1033 // kind of change is occuring in the domain.
1034 //*********************************************************************************
1036 IOReturn
IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1038 unsigned long newStateNumber
;
1040 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogDidChange
,newPowerStateFlags
,0);
1042 setParentInfo(newPowerStateFlags
,whichParent
);
1044 if ( pm_vars
->theControllingDriver
== NULL
) {
1045 return IOPMAckImplied
;
1048 newStateNumber
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(pm_vars
->parentsCurrentPowerFlags
);
1049 return enqueuePowerChange(IOPMParentInitiated
| IOPMDomainDidChange
,
1050 newStateNumber
,pm_vars
->parentsCurrentPowerFlags
,whichParent
,0); // tell interested parties about it
1054 //*********************************************************************************
1057 // Set our connection data for one specific parent, and then combine all the parent
1059 //*********************************************************************************
1061 void IOService::setParentInfo ( IOPMPowerFlags newPowerStateFlags
, IOPowerConnection
* whichParent
)
1065 IOPowerConnection
* connection
;
1067 whichParent
->setParentCurrentPowerFlags(newPowerStateFlags
); // set our connection data
1068 whichParent
->setParentKnowsState(true);
1070 IOLockLock(pm_vars
->parentLock
);
1072 pm_vars
->parentsCurrentPowerFlags
= 0; // recompute our parent info
1073 pm_vars
->parentsKnowState
= true;
1075 iter
= getParentIterator(gIOPowerPlane
);
1078 while ( (next
= iter
->getNextObject()) ) {
1079 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1080 pm_vars
->parentsKnowState
&= connection
->parentKnowsState();
1081 pm_vars
->parentsCurrentPowerFlags
|= connection
->parentCurrentPowerFlags();
1086 IOLockUnlock(pm_vars
->parentLock
);
1089 //*********************************************************************************
1090 // rebuildChildClampBits
1092 // The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1093 // indicate that one of our children (or grandchildren or great-grandchildren or ...)
1094 // doesn't support idle or system sleep in its current state. Since we don't track the
1095 // origin of each bit, every time any child changes state we have to clear these bits
1096 // and rebuild them.
1097 //*********************************************************************************
1099 void IOService::rebuildChildClampBits(void)
1104 IOPowerConnection
* connection
;
1107 // A child's desires has changed. We need to rebuild the child-clamp bits in our
1108 // power state array. Start by clearing the bits in each power state.
1110 for ( i
= 0; i
< pm_vars
->theNumberOfPowerStates
; i
++ ) {
1111 pm_vars
->thePowerStates
[i
].capabilityFlags
&= ~(kIOPMChildClamp
| kIOPMChildClamp2
);
1114 // Now loop through the children. When we encounter the calling child, save
1115 // the computed state as this child's desire. And while we're at it, set the ChildClamp bits
1116 // in any of our states that some child has requested with clamp on.
1118 iter
= getChildIterator(gIOPowerPlane
);
1122 while ( (next
= iter
->getNextObject()) )
1124 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) )
1126 if ( connection
->getPreventIdleSleepFlag() )
1127 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp
;
1128 if ( connection
->getPreventSystemSleepFlag() )
1129 pm_vars
->thePowerStates
[connection
->getDesiredDomainState()].capabilityFlags
|= kIOPMChildClamp2
;
1138 //*********************************************************************************
1139 // requestPowerDomainState
1141 // The kIOPMPreventIdleSleep and/or kIOPMPreventIdleSleep bits may be be set in the parameter.
1142 // It is not considered part of the state specification.
1143 //*********************************************************************************
1144 IOReturn
IOService::requestPowerDomainState ( IOPMPowerFlags desiredState
, IOPowerConnection
* whichChild
, unsigned long specification
)
1147 unsigned long computedState
;
1148 unsigned long theDesiredState
= desiredState
& ~(kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
1151 IOPowerConnection
* connection
;
1153 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDomain
,
1154 (unsigned long)desiredState
,(unsigned long)specification
);
1156 if ( pm_vars
->theControllingDriver
== NULL
) {
1157 return IOPMNotYetInitialized
;
1160 switch (specification
) {
1161 case IOPMLowestState
:
1163 while ( i
< pm_vars
->theNumberOfPowerStates
) {
1164 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1169 if ( i
>= pm_vars
->theNumberOfPowerStates
) {
1170 return IOPMNoSuchState
;
1174 case IOPMNextLowerState
:
1175 i
= pm_vars
->myCurrentState
- 1;
1177 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1183 return IOPMNoSuchState
;
1187 case IOPMHighestState
:
1188 i
= pm_vars
->theNumberOfPowerStates
;
1191 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1196 return IOPMNoSuchState
;
1200 case IOPMNextHigherState
:
1201 i
= pm_vars
->myCurrentState
+ 1;
1202 while ( i
< pm_vars
->theNumberOfPowerStates
) {
1203 if ( ( pm_vars
->thePowerStates
[i
].outputPowerCharacter
& theDesiredState
) == (theDesiredState
& pm_vars
->myCharacterFlags
) ) {
1208 if ( i
== pm_vars
->theNumberOfPowerStates
) {
1209 return IOPMNoSuchState
;
1214 return IOPMBadSpecification
;
1219 IOLockLock(pm_vars
->childLock
);
1221 // Now loop through the children. When we encounter the calling child, save
1222 // the computed state as this child's desire.
1223 iter
= getChildIterator(gIOPowerPlane
);
1226 while ( (next
= iter
->getNextObject()) ) {
1227 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1228 if ( connection
== whichChild
) {
1229 connection
->setDesiredDomainState(computedState
);
1230 connection
->setPreventIdleSleepFlag(desiredState
& kIOPMPreventIdleSleep
);
1231 connection
->setPreventSystemSleepFlag(desiredState
& kIOPMPreventSystemSleep
);
1232 connection
->setChildHasRequestedPower();
1239 // Since a child's power requirements may have changed, clear and rebuild
1240 // kIOPMChildClamp and kIOPMChildClamp2 (idle and system sleep clamps)
1241 rebuildChildClampBits();
1243 IOLockUnlock(pm_vars
->childLock
);
1245 computeDesiredState(); // this may be different now
1247 if ( inPlane(gIOPowerPlane
) &&
1248 (pm_vars
->parentsKnowState
) ) {
1249 changeState(); // change state if all children can now tolerate lower power
1252 if ( priv
->clampOn
) { // are we clamped on, waiting for this child?
1253 priv
->clampOn
= false; // yes, remove the clamp
1254 changePowerStateToPriv(0);
1261 //*********************************************************************************
1262 // temporaryPowerClampOn
1264 // A power domain wants to clamp its power on till it has children which
1265 // will thendetermine the power domain state.
1267 // We enter the highest state until addPowerChild is called.
1268 //*********************************************************************************
1270 IOReturn
IOService::temporaryPowerClampOn ( void )
1272 priv
->clampOn
= true;
1278 //*********************************************************************************
1281 // Some client of our device is asking that we become usable. Although
1282 // this has not come from a subclassed device object, treat it exactly
1283 // as if it had. In this way, subsequent requests for lower power from
1284 // a subclassed device object will pre-empt this request.
1286 // We treat this as a subclass object request to switch to the
1287 // highest power state.
1288 //*********************************************************************************
1290 IOReturn
IOService::makeUsable ( void )
1292 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogMakeUsable
,0,0);
1294 if ( pm_vars
->theControllingDriver
== NULL
) {
1295 priv
->need_to_become_usable
= true;
1298 priv
->deviceDesire
= pm_vars
->theNumberOfPowerStates
- 1;
1299 computeDesiredState();
1300 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1301 return changeState();
1307 //*********************************************************************************
1308 // currentCapability
1310 //*********************************************************************************
1312 IOPMPowerFlags
IOService::currentCapability ( void )
1314 if ( pm_vars
->theControllingDriver
== NULL
) {
1318 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
;
1323 //*********************************************************************************
1324 // changePowerStateTo
1326 // For some reason, our power-controlling driver has decided it needs to change
1327 // power state. We enqueue the power change so that appropriate parties
1328 // will be notified, and then we will instruct the driver to make the change.
1329 //*********************************************************************************
1331 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
1333 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateTo
,ordinal
,0);
1335 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
) {
1336 return IOPMParameterError
;
1338 priv
->driverDesire
= ordinal
;
1339 computeDesiredState();
1340 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1341 return changeState();
1347 //*********************************************************************************
1348 // changePowerStateToPriv
1350 // For some reason, a subclassed device object has decided it needs to change
1351 // power state. We enqueue the power change so that appropriate parties
1352 // will be notified, and then we will instruct the driver to make the change.
1353 //*********************************************************************************
1355 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
1357 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeStateToPriv
,ordinal
,0);
1359 if ( pm_vars
->theControllingDriver
== NULL
) {
1360 return IOPMNotYetInitialized
;
1362 if ( ordinal
>= pm_vars
->theNumberOfPowerStates
) {
1363 return IOPMParameterError
;
1365 priv
->deviceDesire
= ordinal
;
1366 computeDesiredState();
1367 if ( inPlane(gIOPowerPlane
) && (pm_vars
->parentsKnowState
) ) {
1368 return changeState();
1375 //*********************************************************************************
1376 // computeDesiredState
1378 //*********************************************************************************
1380 void IOService::computeDesiredState ( void )
1384 IOPowerConnection
* connection
;
1385 unsigned long newDesiredState
= 0;
1387 // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire.
1389 if ( ! priv
->device_overrides
) {
1390 iter
= getChildIterator(gIOPowerPlane
);
1393 while ( (next
= iter
->getNextObject()) ) {
1394 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1395 if ( connection
->getDesiredDomainState() > newDesiredState
) {
1396 newDesiredState
= connection
->getDesiredDomainState();
1403 if ( priv
->driverDesire
> newDesiredState
) {
1404 newDesiredState
= priv
->driverDesire
;
1408 if ( priv
->deviceDesire
> newDesiredState
) {
1409 newDesiredState
= priv
->deviceDesire
;
1412 priv
->ourDesiredPowerState
= newDesiredState
;
1416 //*********************************************************************************
1419 // A subclass object, our controlling driver, or a power domain child
1420 // has asked for a different power state. Here we compute what new
1421 // state we should enter and enqueue the change (or start it).
1422 //*********************************************************************************
1424 IOReturn
IOService::changeState ( void )
1426 if ( (pm_vars
->theControllingDriver
== NULL
) || // if not fully initialized
1427 ! (inPlane(gIOPowerPlane
)) ||
1428 ! (pm_vars
->parentsKnowState
) ) {
1429 return IOPMNoErr
; // we can do no more
1432 return enqueuePowerChange(IOPMWeInitiated
,priv
->ourDesiredPowerState
,0,0,0);
1436 //*********************************************************************************
1437 // currentPowerConsumption
1439 //*********************************************************************************
1441 unsigned long IOService::currentPowerConsumption ( void )
1443 if ( pm_vars
->theControllingDriver
== NULL
) {
1444 return kIOPMUnknown
;
1446 if ( pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].capabilityFlags
& kIOPMStaticPowerValid
) {
1447 return pm_vars
->thePowerStates
[pm_vars
->myCurrentState
].staticPower
;
1449 return kIOPMUnknown
;
1452 //*********************************************************************************
1455 // The activity tickle with parameter kIOPMSubclassPolicyis not handled
1456 // here and should have been intercepted by the subclass.
1457 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
1458 // flag to be set, and the device state checked. If the device has been
1459 // powered down, it is powered up again.
1460 //*********************************************************************************
1462 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
=0 )
1464 AbsoluteTime uptime
;
1466 if ( type
== kIOPMSuperclassPolicy1
) {
1467 if ( (priv
->activityLock
== NULL
) ||
1468 (pm_vars
->theControllingDriver
== NULL
) ) {
1471 IOTakeLock(priv
->activityLock
);
1472 priv
->device_active
= true;
1474 clock_get_uptime(&uptime
);
1475 priv
->device_active_timestamp
= uptime
;
1477 if ( pm_vars
->myCurrentState
>= stateNumber
) {
1478 IOUnlock(priv
->activityLock
);
1481 IOUnlock(priv
->activityLock
);
1482 pm_vars
->PMcommandGate
->runAction(unIdleDevice
,(void *)stateNumber
);
1488 //*********************************************************************************
1491 // A child is calling to get a pointer to the Power Management workloop.
1492 // We got it or get it from one of our parents.
1493 //*********************************************************************************
1495 IOWorkLoop
* IOService::getPMworkloop ( void )
1500 if ( ! inPlane(gIOPowerPlane
) ) {
1503 if ( pm_vars
->PMworkloop
== NULL
) { // we have no workloop yet
1504 nub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
1506 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
1508 if ( parent
) { // ask one of our parents for the workloop
1509 pm_vars
->PMworkloop
= parent
->getPMworkloop();
1514 return pm_vars
->PMworkloop
;
1518 //*********************************************************************************
1519 // setIdleTimerPeriod
1521 // A subclass policy-maker is going to use our standard idleness
1522 // detection service. Make a command queue and an idle timer and
1523 // connect them to the power management workloop. Finally,
1525 //*********************************************************************************
1527 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
1529 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMsetIdleTimerPeriod
,period
, 0);
1531 priv
->idle_timer_period
= period
;
1534 if ( getPMworkloop() == NULL
) {
1535 return kIOReturnError
;
1537 // make the timer event
1538 if ( priv
->timerEventSrc
== NULL
) {
1539 priv
->timerEventSrc
= IOTimerEventSource::timerEventSource(this,
1540 PM_idle_timer_expired
);
1541 if ( ! priv
->timerEventSrc
||
1542 ( pm_vars
->PMworkloop
->addEventSource( priv
->timerEventSrc
) != kIOReturnSuccess
) ) {
1543 return kIOReturnError
;
1547 if ( priv
->activityLock
== NULL
) {
1548 priv
->activityLock
= IOLockAlloc();
1551 start_PM_idle_timer();
1557 //*********************************************************************************
1558 // start_PM_idle_timer
1560 // The parameter is a pointer to us. Use it to call our timeout method.
1561 //*********************************************************************************
1562 void IOService::start_PM_idle_timer ( void )
1564 AbsoluteTime uptime
;
1570 IOLockLock(priv
->activityLock
);
1572 clock_get_uptime(&uptime
);
1574 /* Calculate time difference using funky macro from clock.h.
1577 SUB_ABSOLUTETIME(&delta
, &(priv
->device_active_timestamp
));
1579 /* Figure it in seconds.
1581 absolutetime_to_nanoseconds(delta
, &delta_ns
);
1582 delta_secs
= delta_ns
/ NSEC_PER_SEC
;
1584 /* Be paranoid about delta somehow exceeding timer period.
1586 if (delta_secs
< priv
->idle_timer_period
) {
1587 delay_secs
= priv
->idle_timer_period
- delta_secs
;
1589 delay_secs
= priv
->idle_timer_period
;
1592 priv
->timerEventSrc
->setTimeout(delay_secs
, NSEC_PER_SEC
);
1594 IOLockUnlock(priv
->activityLock
);
1599 //*********************************************************************************
1600 // PM_idle_timer_expired
1602 // The parameter is a pointer to us. Use it to call our timeout method.
1603 //*********************************************************************************
1605 void PM_idle_timer_expired(OSObject
* ourSelves
, IOTimerEventSource
*)
1607 ((IOService
*)ourSelves
)->PM_idle_timer_expiration();
1611 //*********************************************************************************
1612 // PM_idle_timer_expiration
1614 // The idle timer has expired. If there has been activity since the last
1615 // expiration, just restart the timer and return. If there has not been
1616 // activity, switch to the next lower power state and restart the timer.
1617 //*********************************************************************************
1619 void IOService::PM_idle_timer_expiration ( void )
1621 if ( ! initialized
) {
1622 return; // we're unloading
1625 if ( priv
->idle_timer_period
> 0 ) {
1626 IOTakeLock(priv
->activityLock
);
1627 if ( priv
->device_active
) {
1628 priv
->device_active
= false;
1629 IOUnlock(priv
->activityLock
);
1630 start_PM_idle_timer();
1633 if ( pm_vars
->myCurrentState
> 0 ) {
1634 IOUnlock(priv
->activityLock
);
1635 changePowerStateToPriv(pm_vars
->myCurrentState
- 1);
1636 start_PM_idle_timer();
1639 IOUnlock(priv
->activityLock
);
1640 start_PM_idle_timer();
1646 // **********************************************************************************
1649 // We are behind the command gate. This serializes with respect to timer expiration.
1650 // **********************************************************************************
1651 IOReturn
unIdleDevice ( OSObject
* theDriver
, void * param1
, void * param2
, void * param3
, void * param4
)
1653 ((IOService
*)theDriver
)->command_received(param1
,param2
,param3
,param4
);
1654 return kIOReturnSuccess
;
1658 // **********************************************************************************
1661 // We are un-idling a device due to its activity tickle.
1662 // **********************************************************************************
1663 void IOService::command_received ( void * stateNumber
, void *, void * , void * )
1665 if ( ! initialized
) {
1666 return; // we're unloading
1669 if ( (pm_vars
->myCurrentState
< (unsigned long)stateNumber
) &&
1670 (priv
->imminentState
< (unsigned long)stateNumber
) ) {
1671 changePowerStateToPriv((unsigned long)stateNumber
);
1676 //*********************************************************************************
1677 // setAggressiveness
1679 // Pass on the input parameters to all power domain children. All those which are
1680 // power domains will pass it on to their children, etc.
1681 //*********************************************************************************
1683 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
1687 IOPowerConnection
* connection
;
1690 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSetAggressiveness
,type
, newLevel
);
1692 if ( type
<= kMaxType
) {
1693 pm_vars
->current_aggressiveness_values
[type
] = newLevel
;
1694 pm_vars
->current_aggressiveness_valid
[type
] = true;
1697 iter
= getChildIterator(gIOPowerPlane
);
1700 while ( (next
= iter
->getNextObject()) ) {
1701 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1702 child
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
1704 child
->setAggressiveness(type
, newLevel
);
1715 //*********************************************************************************
1716 // getAggressiveness
1718 // Called by the user client.
1719 //*********************************************************************************
1721 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
1723 if ( type
<= kMaxType
) {
1724 *currentLevel
= pm_vars
->current_aggressiveness_values
[type
];
1726 return kIOReturnSuccess
;
1729 //*********************************************************************************
1732 // Pass this to all power domain children. All those which are
1733 // power domains will pass it on to their children, etc.
1734 //*********************************************************************************
1736 IOReturn
IOService::systemWake ( void )
1740 IOPowerConnection
* connection
;
1741 IOService
* theChild
;
1743 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogSystemWake
,0, 0);
1745 iter
= getChildIterator(gIOPowerPlane
);
1748 while ( (next
= iter
->getNextObject()) ) {
1749 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1750 theChild
= (IOService
*)connection
->copyChildEntry(gIOPowerPlane
);
1752 theChild
->systemWake();
1753 theChild
->release();
1760 if ( pm_vars
->theControllingDriver
!= NULL
) {
1761 if ( pm_vars
->theControllingDriver
->didYouWakeSystem() ) {
1770 //*********************************************************************************
1771 // temperatureCriticalForZone
1773 //*********************************************************************************
1775 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
1777 IOService
* theParent
;
1780 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCriticalTemp
,0,0);
1782 if ( inPlane(gIOPowerPlane
) && ! (priv
->we_are_root
) ) {
1783 theNub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
1785 theParent
= (IOService
*)theNub
->copyParentEntry(gIOPowerPlane
);
1788 theParent
->temperatureCriticalForZone(whichZone
);
1789 theParent
->release();
1797 //*********************************************************************************
1798 // powerOverrideOnPriv
1800 //*********************************************************************************
1803 IOReturn
IOService::powerOverrideOnPriv ( void )
1805 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOn
,0,0);
1807 priv
->device_overrides
= true; // turn on the override
1808 computeDesiredState();
1809 return changeState(); // change state if that changed something
1813 //*********************************************************************************
1814 // powerOverrideOffPriv
1816 //*********************************************************************************
1817 IOReturn
IOService::powerOverrideOffPriv ( void )
1819 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogOverrideOff
,0,0);
1821 priv
->device_overrides
= false; // turn off the override
1822 computeDesiredState();
1824 return makeUsable();
1826 return changeState(); // change state if that changed something
1830 //*********************************************************************************
1831 // enqueuePowerChange
1833 // Allocate a new state change notification, initialize it with fields from the
1834 // caller, and add it to the tail of the list of pending power changes.
1836 // If it is early enough in the list, and almost all the time it is the only one in
1837 // the list, start the power change.
1839 // In rare instances, this change will preempt the previous change in the list.
1840 // If the previous change is un-actioned in any way (because we are still
1841 // processing an even earlier power change), and if both the previous change
1842 // in the list and this change are initiated by us (not the parent), then we
1843 // needn't perform the previous change, so we collapse the list a little.
1844 //*********************************************************************************
1846 IOReturn
IOService::enqueuePowerChange ( unsigned long flags
, unsigned long whatStateOrdinal
, unsigned long domainState
, IOPowerConnection
* whichParent
, unsigned long singleParentState
)
1851 // Create and initialize the new change note
1853 IOLockLock(priv
->queue_lock
);
1854 newNote
= priv
->changeList
->createChangeNote();
1855 if ( newNote
== -1 ) {
1856 IOLockUnlock(priv
->queue_lock
);
1857 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogEnqueueErr
,0,0);
1858 return IOPMAckImplied
; // uh-oh, our list is full
1861 priv
->changeList
->changeNote
[newNote
].newStateNumber
= whatStateOrdinal
;
1862 priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
= pm_vars
->thePowerStates
[whatStateOrdinal
].outputPowerCharacter
;
1863 priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
= pm_vars
->thePowerStates
[whatStateOrdinal
].inputPowerRequirement
;
1864 priv
->changeList
->changeNote
[newNote
].capabilityFlags
= pm_vars
->thePowerStates
[whatStateOrdinal
].capabilityFlags
;
1865 priv
->changeList
->changeNote
[newNote
].flags
= flags
;
1866 if (flags
& IOPMParentInitiated
) {
1867 priv
->changeList
->changeNote
[newNote
].domainState
= domainState
;
1868 priv
->changeList
->changeNote
[newNote
].parent
= whichParent
;
1869 whichParent
->retain();
1870 priv
->changeList
->changeNote
[newNote
].singleParentState
= singleParentState
;
1873 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
1875 if ( previousNote
== -1 ) {
1877 // Queue is empty, we can start this change.
1879 if (flags
& IOPMWeInitiated
) {
1880 IOLockUnlock(priv
->queue_lock
);
1881 start_our_change(newNote
);
1885 IOLockUnlock(priv
->queue_lock
);
1886 return start_parent_change(newNote
);
1890 // The queue is not empty. Try to collapse this new change and the previous one in queue into one change.
1891 // This is possible only if both changes are initiated by us, and neither has been started yet.
1892 // Do this more than once if possible.
1894 // (A change is started iff it is at the head of the queue)
1896 while ( (previousNote
!= priv
->head_note
) && (previousNote
!= -1) &&
1897 (priv
->changeList
->changeNote
[newNote
].flags
& priv
->changeList
->changeNote
[previousNote
].flags
& IOPMWeInitiated
) ) {
1898 priv
->changeList
->changeNote
[previousNote
].outputPowerCharacter
= priv
->changeList
->changeNote
[newNote
].outputPowerCharacter
;
1899 priv
->changeList
->changeNote
[previousNote
].inputPowerRequirement
= priv
->changeList
->changeNote
[newNote
].inputPowerRequirement
;
1900 priv
->changeList
->changeNote
[previousNote
].capabilityFlags
=priv
-> changeList
->changeNote
[newNote
].capabilityFlags
;
1901 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCollapseQueue
,priv
->changeList
->changeNote
[newNote
].newStateNumber
,
1902 priv
->changeList
->changeNote
[previousNote
].newStateNumber
);
1903 priv
->changeList
->changeNote
[previousNote
].newStateNumber
= priv
->changeList
->changeNote
[newNote
].newStateNumber
;
1904 priv
->changeList
->releaseTailChangeNote();
1905 newNote
= previousNote
;
1906 previousNote
= priv
->changeList
->previousChangeNote(newNote
);
1908 IOLockUnlock(priv
->queue_lock
);
1909 return IOPMWillAckLater
; // in any case, we can't start yet
1912 //*********************************************************************************
1915 // Notify all interested parties either that a change is impending or that the
1916 // previously-notified change is done and power has settled.
1917 // The parameter identifies whether this is the
1918 // pre-change notification or the post-change notification.
1920 //*********************************************************************************
1922 IOReturn
IOService::notifyAll ( bool is_prechange
)
1924 IOPMinformee
* nextObject
;
1927 IOPowerConnection
* connection
;
1929 // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if
1930 // some driver calls it, we inflate the number of pending acks so it cannot become zero. We'll fix it later.
1932 priv
->head_note_pendingAcks
=1;
1934 // OK, we will go through the lists of interested drivers and power domain children
1935 // and notify each one of this change.
1936 nextObject
= priv
->interestedDrivers
->firstInList(); // notify interested drivers
1937 while ( nextObject
!= NULL
) {
1938 priv
->head_note_pendingAcks
+=1;
1939 if (! inform(nextObject
, is_prechange
) ) {
1941 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
1944 if (! acquire_lock() ) {
1947 if ( priv
->head_note_pendingAcks
> 1 ) { // did they all ack?
1948 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0); // no
1951 IOUnlock(priv
->our_lock
); // either way
1953 iter
= getChildIterator(gIOPowerPlane
); // notify children
1954 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= 0; // summing their power consumption
1957 while ( (next
= iter
->getNextObject()) ) {
1958 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
1959 priv
->head_note_pendingAcks
+=1;
1960 notifyChild(connection
, is_prechange
);
1966 if (! acquire_lock() ) {
1969 priv
->head_note_pendingAcks
-= 1; // now make this real
1970 if (priv
->head_note_pendingAcks
== 0 ) { // is it all acked?
1971 IOUnlock(priv
->our_lock
); // yes
1972 return IOPMAckImplied
; // return ack to parent
1974 IOUnlock(priv
->our_lock
); // no
1975 return IOPMWillAckLater
;
1979 //*********************************************************************************
1982 // Notify a power domain child of an upcoming power change.
1984 // If the object acknowledges the current change, we return TRUE.
1985 //*********************************************************************************
1987 bool IOService::notifyChild ( IOPowerConnection
* theNub
, bool is_prechange
)
1989 IOReturn k
= IOPMAckImplied
;
1990 unsigned long childPower
;
1991 IOService
* theChild
= (IOService
*)(theNub
->copyChildEntry(gIOPowerPlane
));
1993 theNub
->setAwaitingAck(true); // in case they don't ack
1999 if ( is_prechange
) {
2000 k
= theChild
->powerDomainWillChangeTo(priv
->head_note_outputFlags
,theNub
);
2003 k
= theChild
->powerDomainDidChangeTo(priv
->head_note_outputFlags
,theNub
);
2006 if ( k
== IOPMAckImplied
) { // did the return code ack?
2007 priv
->head_note_pendingAcks
-=1; // yes
2008 theNub
->setAwaitingAck(false);
2009 childPower
= theChild
->currentPowerConsumption();
2010 if ( childPower
== kIOPMUnknown
) {
2011 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
= kIOPMUnknown
;
2014 if ( pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
!= kIOPMUnknown
) {
2015 pm_vars
->thePowerStates
[priv
->head_note_state
].staticPower
+= childPower
;
2018 theChild
->release();
2021 theChild
->release();
2026 //*********************************************************************************
2029 // Notify an interested driver of an upcoming power change.
2031 // If the object acknowledges the current change, we return TRUE.
2032 //*********************************************************************************
2034 bool IOService::inform ( IOPMinformee
* nextObject
, bool is_prechange
)
2036 IOReturn k
= IOPMAckImplied
;
2038 nextObject
->timer
= -1; // initialize this
2040 if ( is_prechange
) {
2041 pm_vars
->thePlatform
->PMLog (pm_vars
->ourName
,PMlogInformDriverPreChange
,
2042 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
2043 k
= nextObject
->whatObject
->powerStateWillChangeTo( priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
2046 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogInformDriverPostChange
,
2047 (unsigned long)priv
->head_note_capabilityFlags
,(unsigned long)priv
->head_note_state
);
2048 k
= nextObject
->whatObject
->powerStateDidChangeTo(priv
->head_note_capabilityFlags
,priv
->head_note_state
,this);
2050 if ( nextObject
->timer
== 0 ) { // did it ack behind our back?
2053 if ( k
==IOPMAckImplied
) { // no, did the return code ack?
2054 nextObject
->timer
= 0; // yes
2055 priv
->head_note_pendingAcks
-= 1;
2059 nextObject
->timer
= 0; // somebody goofed
2060 priv
-> head_note_pendingAcks
-= 1;
2063 nextObject
->timer
= (k
* ns_per_us
/ ACK_TIMER_PERIOD
) + 1; // no, it's a timer
2068 //*********************************************************************************
2071 // All registered applications and kernel clients have positively acknowledged our
2072 // intention of lowering power. Here we notify them all that we will definitely
2073 // lower the power. If we don't have to wait for any of them to acknowledge, we
2074 // carry on by notifying interested drivers. Otherwise, we do wait.
2075 //*********************************************************************************
2077 void IOService::our_prechange_03 ( void )
2079 priv
->machine_state
= IOPMour_prechange_04
; // next state
2080 if ( tellChangeDown1(priv
->head_note_state
) ) { // are we waiting for responses?
2081 our_prechange_04(); // no, notify priority clients
2086 //*********************************************************************************
2089 // All registered applications and kernel clients have positively acknowledged our
2090 // intention of lowering power. Here we notify "priority" clients that we are
2091 // lowering power. If we don't have to wait for any of them to acknowledge, we
2092 // carry on by notifying interested drivers. Otherwise, we do wait.
2093 //*********************************************************************************
2095 void IOService::our_prechange_04 ( void )
2097 priv
->machine_state
= IOPMour_prechange_05
; // next state
2098 if ( tellChangeDown2(priv
->head_note_state
) ) { // are we waiting for responses?
2099 return our_prechange_05(); // no, notify interested drivers
2104 //*********************************************************************************
2107 // All registered applications and kernel clients have acknowledged our notification
2108 // that we are lowering power. Here we notify interested drivers. If we don't have
2109 // to wait for any of them to acknowledge, we instruct our power driver to make the change.
2110 // Otherwise, we do wait.
2111 //*********************************************************************************
2113 void IOService::our_prechange_05 ( void )
2115 priv
->machine_state
= IOPMour_prechange_1
; // no, in case they don't all ack
2116 if ( notifyAll(true) == IOPMAckImplied
) {
2122 //*********************************************************************************
2125 // All interested drivers have acknowledged our pre-change notification of a power
2126 // change we initiated. Here we instruct our controlling driver to make
2127 // the change to the hardware. If it does so, we continue processing
2128 // (waiting for settle and notifying interested parties post-change.)
2129 // If it doesn't, we have to wait for it to acknowledge and then continue.
2130 //*********************************************************************************
2132 void IOService::our_prechange_1 ( void )
2134 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2135 our_prechange_2(); // it's done, carry on
2138 priv
->machine_state
= IOPMour_prechange_2
; // it's not, wait for it
2139 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2145 //*********************************************************************************
2148 // Our controlling driver has changed power state on the hardware
2149 // during a power change we initiated. Here we see if we need to wait
2150 // for power to settle before continuing. If not, we continue processing
2151 // (notifying interested parties post-change). If so, we wait and
2153 //*********************************************************************************
2155 void IOService::our_prechange_2 ( void )
2157 priv
->settle_time
= compute_settle_time();
2158 if ( priv
->settle_time
== 0 ) {
2162 priv
->machine_state
= IOPMour_prechange_3
;
2163 startSettleTimer(priv
->settle_time
);
2168 //*********************************************************************************
2171 // Power has settled on a power change we initiated. Here we notify
2172 // all our interested parties post-change. If they all acknowledge, we're
2173 // done with this change note, and we can start on the next one.
2174 // Otherwise we have to wait for acknowledgements and finish up later.
2175 //*********************************************************************************
2177 void IOService::our_prechange_3 ( void )
2179 priv
->machine_state
= IOPMour_prechange_4
; // in case they don't all ack
2180 if ( notifyAll(false) == IOPMAckImplied
) {
2186 //*********************************************************************************
2189 // Power has settled on a power change we initiated, and
2190 // all our interested parties have acknowledged. We're
2191 // done with this change note, and we can start on the next one.
2192 //*********************************************************************************
2194 void IOService::our_prechange_4 ( void )
2200 //*********************************************************************************
2203 // All applications and kernel clients have been notified of a power lowering
2204 // initiated by the parent and we didn't have to wait for any responses. Here
2205 // we notify any priority clients. If they all ack, we continue with the power change.
2206 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2207 //*********************************************************************************
2209 IOReturn
IOService::parent_down_0 ( void )
2211 priv
->machine_state
= IOPMparent_down_05
; // in case they don't all ack
2212 if ( tellChangeDown2(priv
->head_note_state
) ) { // are we waiting for responses?
2213 return parent_down_02(); // no, notify interested drivers
2215 return IOPMWillAckLater
; // they didn't
2219 //*********************************************************************************
2222 // All priority kernel clients have been notified of a power lowering
2223 // initiated by the parent and we didn't have to wait for any responses. Here
2224 // we notify any interested drivers and power domain children. If they all ack,
2225 // we continue with the power change.
2226 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2227 //*********************************************************************************
2229 IOReturn
IOService::parent_down_02 ( void )
2231 priv
->machine_state
= IOPMparent_down_4
; // in case they don't all ack
2232 if ( notifyAll(true) == IOPMAckImplied
) {
2233 return parent_down_1(); // they did
2235 return IOPMWillAckLater
; // they didn't
2239 //*********************************************************************************
2242 // All applications and kernel clients have been notified of a power lowering
2243 // initiated by the parent and we had to wait for responses. Here
2244 // we notify any priority clients. If they all ack, we continue with the power change.
2245 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2246 //*********************************************************************************
2248 void IOService::parent_down_04 ( void )
2250 priv
->machine_state
= IOPMparent_down_05
; // in case they don't all ack
2251 if ( tellChangeDown2(priv
->head_note_state
) ) { // are we waiting for responses?
2252 parent_down_05(); // no, notify interested drivers
2257 //*********************************************************************************
2260 // All applications and kernel clients have been notified of a power lowering
2261 // initiated by the parent and we had to wait for their responses. Here we notify
2262 // any interested drivers and power domain children. If they all ack, we continue
2263 // with the power change.
2264 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
2265 //*********************************************************************************
2267 void IOService::parent_down_05 ( void )
2269 priv
->machine_state
= IOPMparent_down_4
; // in case they don't all ack
2270 if ( notifyAll(true) == IOPMAckImplied
) {
2271 parent_down_4(); // they did
2276 //*********************************************************************************
2279 // All parties have acknowledged our pre-change notification of a power
2280 // lowering initiated by the parent. Here we instruct our controlling driver
2281 // to put the hardware in the state it needs to be in when the domain is
2282 // lowered. If it does so, we continue processing
2283 // (waiting for settle and acknowledging the parent.)
2284 // If it doesn't, we have to wait for it to acknowledge and then continue.
2285 //*********************************************************************************
2287 IOReturn
IOService::parent_down_1 ( void )
2289 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2290 return parent_down_2(); // it's done, carry on
2292 priv
->machine_state
= IOPMparent_down_5
; // it's not, wait for it
2293 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2295 return IOPMWillAckLater
;
2299 //*********************************************************************************
2302 // We had to wait for it, but all parties have acknowledged our pre-change
2303 // notification of a power lowering initiated by the parent.
2304 // Here we instruct our controlling driver
2305 // to put the hardware in the state it needs to be in when the domain is
2306 // lowered. If it does so, we continue processing
2307 // (waiting for settle and acknowledging the parent.)
2308 // If it doesn't, we have to wait for it to acknowledge and then continue.
2309 //*********************************************************************************
2311 void IOService::parent_down_4 ( void )
2313 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2314 parent_down_5(); // it's done, carry on
2317 priv
-> machine_state
= IOPMparent_down_5
; // it's not, wait for it
2318 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2324 //*********************************************************************************
2327 // Our controlling driver has changed power state on the hardware
2328 // during a power change initiated by our parent. Here we see if we need
2329 // to wait for power to settle before continuing. If not, we continue
2330 // processing (acknowledging our preparedness to the parent).
2331 // If so, we wait and continue later.
2332 //*********************************************************************************
2334 IOReturn
IOService::parent_down_2 ( void )
2338 priv
->settle_time
= compute_settle_time();
2339 if ( priv
->settle_time
== 0 ) {
2340 priv
->machine_state
= IOPMparent_down_6
; // in case they don't all ack
2341 if ( notifyAll(false) == IOPMAckImplied
) {
2342 nub
= priv
->head_note_parent
;
2345 return IOPMAckImplied
;
2347 return IOPMWillAckLater
; // they didn't
2350 priv
->machine_state
= IOPMparent_down_3
;
2351 startSettleTimer(priv
->settle_time
);
2352 return IOPMWillAckLater
;
2357 //*********************************************************************************
2360 // Our controlling driver has changed power state on the hardware
2361 // during a power change initiated by our parent. We have had to wait
2362 // for acknowledgement from interested parties, or we have had to wait
2363 // for the controlling driver to change the state. Here we see if we need
2364 // to wait for power to settle before continuing. If not, we continue
2365 // processing (acknowledging our preparedness to the parent).
2366 // If so, we wait and continue later.
2367 //*********************************************************************************
2369 void IOService::parent_down_5 ( void )
2371 priv
->settle_time
= compute_settle_time();
2372 if ( priv
->settle_time
== 0 ) {
2376 priv
->machine_state
= IOPMparent_down_3
;
2377 startSettleTimer(priv
->settle_time
);
2382 //*********************************************************************************
2385 // Power has settled on a power change initiated by our parent. Here we
2386 // notify interested parties.
2387 //*********************************************************************************
2389 void IOService::parent_down_3 ( void )
2391 IORegistryEntry
* nub
;
2394 priv
->machine_state
= IOPMparent_down_6
; // in case they don't all ack
2395 if ( notifyAll(false) == IOPMAckImplied
) {
2396 nub
= priv
->head_note_parent
;
2398 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2400 parent
->acknowledgePowerChange((IOService
*)nub
);
2408 //*********************************************************************************
2411 // We had to wait for it, but all parties have acknowledged our post-change
2412 // notification of a power lowering initiated by the parent.
2413 // Here we acknowledge the parent.
2414 // We are done with this change note, and we can start on the next one.
2415 //*********************************************************************************
2417 void IOService::parent_down_6 ( void )
2419 IORegistryEntry
* nub
;
2422 nub
= priv
->head_note_parent
;
2424 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2426 parent
->acknowledgePowerChange((IOService
*)nub
);
2433 //*********************************************************************************
2436 // Our parent has informed us via powerStateDidChange that it has
2437 // raised the power in our power domain, and we have had to wait
2438 // for some interested party to acknowledge our notification.
2439 // Here we instruct our controlling
2440 // driver to program the hardware to take advantage of the higher domain
2441 // power. If it does so, we continue processing
2442 // (waiting for settle and notifying interested parties post-change.)
2443 // If it doesn't, we have to wait for it to acknowledge and then continue.
2444 //*********************************************************************************
2446 void IOService::parent_up_0 ( void )
2448 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2449 parent_up_4(); // it did it, carry on
2452 priv
->machine_state
= IOPMparent_up_4
; // it didn't, wait for it
2453 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2459 //*********************************************************************************
2462 // Our parent has informed us via powerStateDidChange that it has
2463 // raised the power in our power domain. Here we instruct our controlling
2464 // driver to program the hardware to take advantage of the higher domain
2465 // power. If it does so, we continue processing
2466 // (waiting for settle and notifying interested parties post-change.)
2467 // If it doesn't, we have to wait for it to acknowledge and then continue.
2468 //*********************************************************************************
2470 IOReturn
IOService::parent_up_1 ( void )
2472 if ( instruct_driver(priv
->head_note_state
) == IOPMAckImplied
) {
2473 return parent_up_2(); // it did it, carry on
2476 priv
->machine_state
= IOPMparent_up_4
; // it didn't, wait for it
2477 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,0,0);
2479 return IOPMWillAckLater
;
2484 //*********************************************************************************
2487 // Our controlling driver has changed power state on the hardware
2488 // during a power raise initiated by the parent. Here we see if we need to wait
2489 // for power to settle before continuing. If not, we continue processing
2490 // (notifying interested parties post-change). If so, we wait and
2492 //*********************************************************************************
2494 IOReturn
IOService::parent_up_2 ( void )
2496 priv
->settle_time
= compute_settle_time();
2497 if ( priv
->settle_time
== 0 ) {
2498 return parent_up_3();
2501 priv
->machine_state
= IOPMparent_up_5
;
2502 startSettleTimer(priv
->settle_time
);
2503 return IOPMWillAckLater
;
2508 //*********************************************************************************
2511 // Our controlling driver has changed power state on the hardware
2512 // during a power raise initiated by the parent, but we had to wait for it.
2513 // Here we see if we need to wait for power to settle before continuing.
2514 // If not, we continue processing (notifying interested parties post-change).
2515 // If so, we wait and continue later.
2516 //*********************************************************************************
2518 void IOService::parent_up_4 ( void )
2520 priv
->settle_time
= compute_settle_time();
2521 if ( priv
->settle_time
== 0 ) {
2525 priv
->machine_state
= IOPMparent_up_5
;
2526 startSettleTimer(priv
->settle_time
);
2531 //*********************************************************************************
2534 // No power settling was required on a power raise initiated by the parent.
2535 // Here we notify all our interested parties post-change. If they all acknowledge,
2536 // we're done with this change note, and we can start on the next one.
2537 // Otherwise we have to wait for acknowledgements and finish up later.
2538 //*********************************************************************************
2540 IOReturn
IOService::parent_up_3 ( void )
2544 priv
->machine_state
= IOPMparent_up_6
; // in case they don't all ack
2545 if ( notifyAll(false) == IOPMAckImplied
) {
2546 nub
= priv
->head_note_parent
;
2549 return IOPMAckImplied
;
2551 return IOPMWillAckLater
; // they didn't
2555 //*********************************************************************************
2558 // Power has settled on a power raise initiated by the parent.
2559 // Here we notify all our interested parties post-change. If they all acknowledge,
2560 // we're done with this change note, and we can start on the next one.
2561 // Otherwise we have to wait for acknowledgements and finish up later.
2562 //*********************************************************************************
2564 void IOService::parent_up_5 ( void )
2566 priv
->machine_state
= IOPMparent_up_6
; // in case they don't all ack
2567 if ( notifyAll(false) == IOPMAckImplied
) {
2573 //*********************************************************************************
2576 // All parties have acknowledged our post-change notification of a power
2577 // raising initiated by the parent. Here we acknowledge the parent.
2578 // We are done with this change note, and we can start on the next one.
2579 //*********************************************************************************
2581 void IOService::parent_up_6 ( void )
2583 IORegistryEntry
* nub
;
2586 nub
= priv
->head_note_parent
;
2588 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2590 parent
->acknowledgePowerChange((IOService
*)nub
);
2597 //*********************************************************************************
2600 // A power change is complete, and the used post-change note is at
2601 // the head of the queue. Remove it and set myCurrentState to the result
2602 // of the change. Start up the next change in queue.
2603 //*********************************************************************************
2605 void IOService::all_done ( void )
2607 unsigned long previous_state
;
2608 IORegistryEntry
* nub
;
2611 priv
->machine_state
= IOPMfinished
;
2613 if ( priv
->head_note_flags
& IOPMWeInitiated
) { // our power change
2614 if ( !( priv
->head_note_flags
& IOPMNotDone
) ) { // could our driver switch to the new state?
2615 if ( pm_vars
->myCurrentState
< priv
->head_note_state
) { // yes, did power raise?
2616 tellChangeUp (priv
->head_note_state
); // yes, inform clients and apps
2619 if ( ! priv
->we_are_root
) { // no, if this lowers our
2620 ask_parent(priv
->head_note_state
); // power requirements, tell the parent
2623 previous_state
= pm_vars
->myCurrentState
;
2624 pm_vars
->myCurrentState
= priv
->head_note_state
; // either way
2625 priv
->imminentState
= pm_vars
->myCurrentState
;
2626 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
2627 powerChangeDone(previous_state
); // inform subclass policy-maker
2630 // pm_vars->myCurrentState = pm_vars->theControllingDriver->powerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
2633 if ( priv
->head_note_flags
& IOPMParentInitiated
) { // parent's power change
2634 if ( ((priv
->head_note_flags
& IOPMDomainWillChange
) && (pm_vars
->myCurrentState
>= priv
->head_note_state
)) ||
2635 ((priv
->head_note_flags
& IOPMDomainDidChange
) && (pm_vars
->myCurrentState
< priv
->head_note_state
)) ) {
2636 if ( pm_vars
->myCurrentState
< priv
->head_note_state
) { // did power raise?
2637 tellChangeUp (priv
->head_note_state
); // yes, inform clients and apps
2639 previous_state
= pm_vars
->myCurrentState
; // either way
2640 pm_vars
->myCurrentState
= priv
->head_note_state
;
2641 priv
->imminentState
= pm_vars
->myCurrentState
;
2642 pm_vars
->maxCapability
= pm_vars
->theControllingDriver
->maxCapabilityForDomainState(priv
->head_note_domainState
);
2644 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogChangeDone
,(unsigned long)pm_vars
->myCurrentState
,0);
2645 powerChangeDone(previous_state
); // inform subclass policy-maker
2649 IOLockLock(priv
->queue_lock
);
2650 priv
->changeList
->releaseHeadChangeNote(); // we're done with this
2652 priv
->head_note
= priv
->changeList
->currentChange(); // start next one in queue
2653 if ( priv
->head_note
!= -1 ) {
2655 IOLockUnlock(priv
->queue_lock
);
2656 if (priv
->changeList
->changeNote
[priv
->head_note
].flags
& IOPMWeInitiated
) {
2657 start_our_change(priv
->head_note
);
2660 nub
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
2661 if ( start_parent_change(priv
->head_note
) == IOPMAckImplied
) {
2662 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
2664 parent
->acknowledgePowerChange((IOService
*)nub
);
2670 IOLockUnlock(priv
->queue_lock
);
2675 //*********************************************************************************
2678 // A driver or child has acknowledged our notification of an upcoming power
2679 // change, and this acknowledgement is the last one pending
2680 // before we change power or after changing power.
2682 //*********************************************************************************
2684 void IOService::all_acked ( void )
2686 switch (priv
->machine_state
) {
2687 case IOPMour_prechange_1
:
2690 case IOPMour_prechange_4
:
2693 case IOPMparent_down_4
:
2696 case IOPMparent_down_6
:
2699 case IOPMparent_up_0
:
2702 case IOPMparent_up_6
:
2709 //*********************************************************************************
2710 // settleTimerExpired
2712 // Power has settled after our last change. Notify interested parties that
2713 // there is a new power state.
2714 //*********************************************************************************
2716 void IOService::settleTimerExpired ( void )
2718 if ( ! initialized
) {
2719 return; // we're unloading
2722 switch (priv
->machine_state
) {
2723 case IOPMour_prechange_3
:
2726 case IOPMparent_down_3
:
2729 case IOPMparent_up_5
:
2736 //*********************************************************************************
2737 // compute_settle_time
2739 // Compute the power-settling delay in microseconds for the
2740 // change from myCurrentState to head_note_state.
2741 //*********************************************************************************
2743 unsigned long IOService::compute_settle_time ( void )
2745 unsigned long totalTime
;
2748 totalTime
= 0; // compute total time to attain the new state
2749 i
= pm_vars
->myCurrentState
;
2750 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // we're lowering power
2751 while ( i
> priv
->head_note_state
) {
2752 totalTime
+= pm_vars
->thePowerStates
[i
].settleDownTime
;
2757 if ( priv
->head_note_state
> pm_vars
->myCurrentState
) { // we're raising power
2758 while ( i
< priv
->head_note_state
) {
2759 totalTime
+= pm_vars
->thePowerStates
[i
+1].settleUpTime
;
2768 //*********************************************************************************
2771 // Enter with a power-settling delay in microseconds and start a nano-second
2772 // timer for that delay.
2773 //*********************************************************************************
2775 IOReturn
IOService::startSettleTimer ( unsigned long delay
)
2777 AbsoluteTime deadline
;
2779 clock_interval_to_deadline(delay
, kMicrosecondScale
, &deadline
);
2781 thread_call_enter_delayed(priv
->settleTimer
, deadline
);
2786 //*********************************************************************************
2789 // The acknowledgement timeout periodic timer has ticked.
2790 // If we are awaiting acks for a power change notification,
2791 // we decrement the timer word of each interested driver which hasn't acked.
2792 // If a timer word becomes zero, we pretend the driver aknowledged.
2793 // If we are waiting for the controlling driver to change the power
2794 // state of the hardware, we decrement its timer word, and if it becomes
2795 // zero, we pretend the driver acknowledged.
2796 //*********************************************************************************
2798 void IOService::ack_timer_ticked ( void )
2800 IOPMinformee
* nextObject
;
2802 if ( ! initialized
) {
2803 return; // we're unloading
2806 if (! acquire_lock() ) {
2810 switch (priv
->machine_state
) {
2811 case IOPMour_prechange_2
:
2812 case IOPMparent_down_5
:
2813 case IOPMparent_up_4
:
2814 if ( priv
->driver_timer
!= 0 ) { // are we waiting for our driver to make its change?
2815 priv
->driver_timer
-= 1; // yes, tick once
2816 if ( priv
->driver_timer
== 0 ) { // it's tardy, we'll go on without it
2817 IOUnlock(priv
->our_lock
);
2818 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogCtrlDriverTardy
,0,0);
2821 else { // still waiting, set timer again
2823 IOUnlock(priv
->our_lock
);
2827 IOUnlock(priv
->our_lock
);
2831 case IOPMour_prechange_1
:
2832 case IOPMour_prechange_4
:
2833 case IOPMparent_down_4
:
2834 case IOPMparent_down_6
:
2835 case IOPMparent_up_0
:
2836 case IOPMparent_up_6
:
2837 if (priv
->head_note_pendingAcks
!= 0 ) { // are we waiting for interested parties to acknowledge?
2838 nextObject
= priv
->interestedDrivers
->firstInList(); // yes, go through the list of interested drivers
2839 while ( nextObject
!= NULL
) { // and check each one
2840 if ( nextObject
->timer
> 0 ) {
2841 nextObject
->timer
-= 1;
2842 if ( nextObject
->timer
== 0 ) { // this one should have acked by now
2843 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogIntDriverTardy
,0,0);
2844 kprintf("interested driver tardy: %s\n",nextObject
->whatObject
->getName());
2845 priv
->head_note_pendingAcks
-= 1;
2848 nextObject
= priv
->interestedDrivers
->nextInList(nextObject
);
2850 if ( priv
->head_note_pendingAcks
== 0 ) { // is that the last?
2851 IOUnlock(priv
->our_lock
);
2852 all_acked(); // yes, we can continue
2854 else { // no, set timer again
2856 IOUnlock(priv
->our_lock
);
2860 IOUnlock(priv
->our_lock
);
2864 case IOPMparent_down_0
: // apps didn't respond to parent-down notification
2865 IOUnlock(priv
->our_lock
);
2866 IOLockLock(priv
->flags_lock
);
2867 if (pm_vars
->responseFlags
) {
2868 pm_vars
->responseFlags
->release(); // get rid of this stuff
2869 pm_vars
->responseFlags
= NULL
;
2871 IOLockUnlock(priv
->flags_lock
);
2872 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,5);
2873 parent_down_04(); // carry on with the change
2876 case IOPMparent_down_05
:
2877 IOUnlock(priv
->our_lock
);
2878 IOLockLock(priv
->flags_lock
);
2879 if (pm_vars
->responseFlags
) {
2880 pm_vars
->responseFlags
->release(); // get rid of this stuff
2881 pm_vars
->responseFlags
= NULL
;
2883 IOLockUnlock(priv
->flags_lock
);
2884 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,1);
2885 parent_down_05(); // carry on with the change
2888 case IOPMour_prechange_03
: // apps didn't respond to our power-down request
2889 IOUnlock(priv
->our_lock
);
2890 IOLockLock(priv
->flags_lock
);
2891 if (pm_vars
->responseFlags
) {
2892 pm_vars
->responseFlags
->release(); // get rid of this stuff
2893 pm_vars
->responseFlags
= NULL
;
2895 IOLockUnlock(priv
->flags_lock
);
2896 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,2);
2897 tellNoChangeDown(priv
->head_note_state
); // rescind the request
2898 priv
->head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
2899 all_done(); // and we're done
2902 case IOPMour_prechange_04
: // clients didn't respond to our power-down note
2903 IOUnlock(priv
->our_lock
);
2904 IOLockLock(priv
->flags_lock
);
2905 if (pm_vars
->responseFlags
) {
2906 pm_vars
->responseFlags
->release(); // get rid of this stuff
2907 pm_vars
->responseFlags
= NULL
;
2909 IOLockUnlock(priv
->flags_lock
);
2910 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,4);
2911 our_prechange_04(); // carry on with the change
2914 case IOPMour_prechange_05
: // apps didn't respond to our power-down notification
2915 IOUnlock(priv
->our_lock
);
2916 IOLockLock(priv
->flags_lock
);
2917 if (pm_vars
->responseFlags
) {
2918 pm_vars
->responseFlags
->release(); // get rid of this stuff
2919 pm_vars
->responseFlags
= NULL
;
2921 IOLockUnlock(priv
->flags_lock
);
2922 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientTardy
,0,3);
2923 our_prechange_05(); // carry on with the change
2927 IOUnlock(priv
->our_lock
); // not waiting for acks
2933 //*********************************************************************************
2936 //*********************************************************************************
2938 void IOService::start_ack_timer ( void )
2940 AbsoluteTime deadline
;
2942 clock_interval_to_deadline(ACK_TIMER_PERIOD
, kNanosecondScale
, &deadline
);
2944 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
2948 //*********************************************************************************
2951 //*********************************************************************************
2953 void IOService::stop_ack_timer ( void )
2955 thread_call_cancel(priv
->ackTimer
);
2959 //*********************************************************************************
2960 // c-language timer expiration functions
2962 //*********************************************************************************
2964 static void ack_timer_expired ( thread_call_param_t us
)
2966 ((IOService
*)us
)->ack_timer_ticked();
2970 static void settle_timer_expired ( thread_call_param_t us
)
2972 ((IOService
*)us
)->settleTimerExpired();
2976 //*********************************************************************************
2977 // add_child_to_active_change
2979 // A child has just registered with us. If there is
2980 // currently a change in progress, get the new party involved: if we
2981 // have notified all parties and are waiting for acks, notify the new
2983 //*********************************************************************************
2985 IOReturn
IOService::add_child_to_active_change ( IOPowerConnection
* newObject
)
2987 if (! acquire_lock() ) {
2991 switch (priv
->machine_state
) {
2992 case IOPMour_prechange_1
:
2993 case IOPMparent_down_4
:
2994 case IOPMparent_up_0
:
2995 priv
->head_note_pendingAcks
+= 2; // one for this child and one to prevent
2996 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
2997 notifyChild(newObject
, true);
2998 if (! acquire_lock() ) {
2999 --priv
->head_note_pendingAcks
; // put it back
3002 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
3003 stop_ack_timer(); // no, stop the timer
3004 IOUnlock(priv
->our_lock
);
3005 all_acked(); // and now we can continue
3009 case IOPMour_prechange_4
:
3010 case IOPMparent_down_6
:
3011 case IOPMparent_up_6
:
3012 priv
->head_note_pendingAcks
+= 2; // one for this child and one to prevent
3013 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
3014 notifyChild(newObject
, false);
3015 if (! acquire_lock() ) {
3016 --priv
->head_note_pendingAcks
; // put it back
3019 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
3020 stop_ack_timer(); // no, stop the timer
3021 IOUnlock(priv
->our_lock
);
3022 all_acked(); // and now we can continue
3027 IOUnlock(priv
->our_lock
);
3032 //*********************************************************************************
3033 // add_driver_to_active_change
3035 // An interested driver has just registered with us. If there is
3036 // currently a change in progress, get the new party involved: if we
3037 // have notified all parties and are waiting for acks, notify the new
3039 //*********************************************************************************
3041 IOReturn
IOService::add_driver_to_active_change ( IOPMinformee
* newObject
)
3043 if (! acquire_lock() ) {
3047 switch (priv
->machine_state
) {
3048 case IOPMour_prechange_1
:
3049 case IOPMparent_down_4
:
3050 case IOPMparent_up_0
:
3051 priv
->head_note_pendingAcks
+= 2; // one for this driver and one to prevent
3052 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
3053 inform(newObject
, true); // inform the driver
3054 if (! acquire_lock() ) {
3055 --priv
->head_note_pendingAcks
; // put it back
3058 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
3059 stop_ack_timer(); // no, stop the timer
3060 IOUnlock(priv
->our_lock
);
3061 all_acked(); // and now we can continue
3065 case IOPMour_prechange_4
:
3066 case IOPMparent_down_6
:
3067 case IOPMparent_up_6
:
3068 priv
->head_note_pendingAcks
+= 2; // one for this driver and one to prevent
3069 IOUnlock(priv
->our_lock
); // incoming acks from changing our state
3070 inform(newObject
, false); // inform the driver
3071 if (! acquire_lock() ) {
3072 --priv
->head_note_pendingAcks
; // put it back
3075 if ( --priv
->head_note_pendingAcks
== 0 ) { // are we still waiting for acks?
3076 stop_ack_timer(); // no, stop the timer
3077 IOUnlock(priv
->our_lock
);
3078 all_acked(); // and now we can continue
3083 IOUnlock(priv
->our_lock
);
3088 //*********************************************************************************
3089 // start_parent_change
3091 // Here we begin the processing of a change note initiated by our parent
3092 // which is at the head of the queue.
3094 // It is possible for the change to be processed to completion and removed from the queue.
3095 // There are several possible interruptions to the processing, though, and they are:
3096 // we may have to wait for interested parties to acknowledge our pre-change notification,
3097 // we may have to wait for our controlling driver to change the hardware power state,
3098 // there may be a settling time after changing the hardware power state,
3099 // we may have to wait for interested parties to acknowledge our post-change notification,
3100 // we may have to wait for the acknowledgement timer expiration to substitute for the
3101 // acknowledgement from a failing driver.
3102 //*********************************************************************************
3104 IOReturn
IOService::start_parent_change ( unsigned long queue_head
)
3106 priv
->head_note
= queue_head
;
3107 priv
->head_note_flags
= priv
-> changeList
->changeNote
[priv
->head_note
].flags
;
3108 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3109 priv
->imminentState
= priv
->head_note_state
;
3110 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3111 priv
->head_note_domainState
= priv
->changeList
->changeNote
[priv
->head_note
].domainState
;
3112 priv
->head_note_parent
= priv
->changeList
->changeNote
[priv
->head_note
].parent
;
3113 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3115 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartParentChange
,
3116 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3118 ask_parent( priv
->ourDesiredPowerState
); // if we need something and haven't told the parent, do so
3120 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // power domain is lowering
3121 setParentInfo(priv
->changeList
->changeNote
[priv
->head_note
].singleParentState
,priv
->head_note_parent
);
3122 priv
->initial_change
= false;
3123 priv
->machine_state
= IOPMparent_down_0
; // tell apps and kernel clients
3124 if ( tellChangeDown1(priv
->head_note_state
) ) { // are we waiting for responses?
3125 return parent_down_0(); // no, notify priority clients
3127 return IOPMWillAckLater
; // yes
3130 if ( priv
->head_note_state
> pm_vars
->myCurrentState
) { // parent is raising power, we may or may not
3131 if ( priv
->ourDesiredPowerState
> pm_vars
->myCurrentState
) {
3132 if ( priv
->ourDesiredPowerState
< priv
->head_note_state
) {
3133 priv
->head_note_state
= priv
->ourDesiredPowerState
; // we do, but not all the way
3134 priv
->imminentState
= priv
->head_note_state
;
3135 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3136 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3137 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3141 priv
->head_note_state
= pm_vars
->myCurrentState
; // we don't
3142 priv
->imminentState
= priv
->head_note_state
;
3143 priv
->head_note_outputFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].outputPowerCharacter
;
3144 priv
->head_note_capabilityFlags
= pm_vars
->thePowerStates
[priv
->head_note_state
].capabilityFlags
;
3145 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAmendParentChange
,(unsigned long)priv
->head_note_state
,0);
3149 if ( (priv
->head_note_state
> pm_vars
->myCurrentState
) &&
3150 (priv
->head_note_flags
& IOPMDomainDidChange
) ) { // changing up
3151 priv
->initial_change
= false;
3152 priv
->machine_state
= IOPMparent_up_0
;
3153 if ( notifyAll(true) == IOPMAckImplied
) {
3154 return parent_up_1();
3156 return IOPMWillAckLater
; // they didn't all ack
3160 return IOPMAckImplied
; // a null change or power will go up
3164 //*********************************************************************************
3167 // Here we begin the processing of a change note initiated by us
3168 // which is at the head of the queue.
3170 // It is possible for the change to be processed to completion and removed from the queue.
3171 // There are several possible interruptions to the processing, though, and they are:
3172 // we may have to wait for interested parties to acknowledge our pre-change notification,
3173 // changes initiated by the parent will wait in the middle for powerStateDidChange,
3174 // we may have to wait for our controlling driver to change the hardware power state,
3175 // there may be a settling time after changing the hardware power state,
3176 // we may have to wait for interested parties to acknowledge our post-change notification,
3177 // we may have to wait for the acknowledgement timer expiration to substitute for the
3178 // acknowledgement from a failing driver.
3179 //*********************************************************************************
3181 void IOService::start_our_change ( unsigned long queue_head
)
3183 priv
->head_note
= queue_head
;
3184 priv
->head_note_flags
= priv
->changeList
->changeNote
[priv
->head_note
].flags
;
3185 priv
->head_note_state
= priv
->changeList
->changeNote
[priv
->head_note
].newStateNumber
;
3186 priv
->imminentState
= priv
->head_note_state
;
3187 priv
->head_note_outputFlags
= priv
->changeList
->changeNote
[priv
->head_note
].outputPowerCharacter
;
3188 priv
->head_note_capabilityFlags
= priv
->changeList
->changeNote
[priv
->head_note
].capabilityFlags
;
3190 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartDeviceChange
,
3191 (unsigned long)priv
->head_note_state
,(unsigned long)pm_vars
->myCurrentState
);
3193 if ( priv
->head_note_capabilityFlags
& IOPMNotAttainable
) { // can our driver switch to the new state?
3194 if ( ! priv
->we_are_root
) { // no, ask the parent to do it then
3195 ask_parent(priv
->head_note_state
);
3197 priv
-> head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3198 all_done(); // and we're done
3201 // is there enough power in the domain?
3202 if ( (pm_vars
->maxCapability
< priv
->head_note_state
) && (! priv
->we_are_root
) ) {
3203 if ( ! priv
->we_are_root
) { // no, ask the parent to raise it
3204 ask_parent(priv
->head_note_state
);
3206 priv
->head_note_flags
|= IOPMNotDone
; // no, mark the change note un-actioned
3207 all_done(); // and we're done
3208 return; // till the parent raises power
3211 if ( ! priv
->initial_change
) {
3212 if ( priv
->head_note_state
== pm_vars
->myCurrentState
) {
3213 all_done(); // we initiated a null change; forget it
3217 priv
->initial_change
= false;
3219 if ( priv
->head_note_state
< pm_vars
->myCurrentState
) { // dropping power?
3220 priv
->machine_state
= IOPMour_prechange_03
; // yes, in case we have to wait for acks
3221 pm_vars
->doNotPowerDown
= false;
3222 pm_vars
->outofbandparameter
= kNotifyApps
; // ask apps and kernel clients if we can drop power
3223 if ( askChangeDown(priv
->head_note_state
) ) {
3224 if ( pm_vars
->doNotPowerDown
) { // don't have to wait, did any clients veto?
3225 tellNoChangeDown(priv
->head_note_state
); // yes, rescind the warning
3226 priv
-> head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3227 all_done(); // and we're done
3230 our_prechange_03(); // no, tell'em we're dropping power
3235 if ( ! priv
->we_are_root
) { // we are raising power
3236 ask_parent(priv
->head_note_state
); // if this changes our power requirement, tell the parent
3238 priv
->machine_state
= IOPMour_prechange_1
; // in case they don't all ack
3239 if ( notifyAll(true) == IOPMAckImplied
) { // notify interested drivers and children
3246 //*********************************************************************************
3249 // Call the power domain parent to ask for a higher power state in the domain
3250 // or to suggest a lower power state.
3251 //*********************************************************************************
3253 IOReturn
IOService::ask_parent ( unsigned long requestedState
)
3257 IOPowerConnection
* connection
;
3259 unsigned long ourRequest
= pm_vars
->thePowerStates
[requestedState
].inputPowerRequirement
;
3261 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp
| kIOPMPreventIdleSleep
) ) {
3262 ourRequest
|= kIOPMPreventIdleSleep
;
3264 if ( pm_vars
->thePowerStates
[requestedState
].capabilityFlags
& (kIOPMChildClamp2
| kIOPMPreventSystemSleep
) ) {
3265 ourRequest
|= kIOPMPreventSystemSleep
;
3268 // is this a new desire?
3269 if ( priv
->previousRequest
== ourRequest
)
3271 // no, the parent knows already, just return
3275 if ( priv
->we_are_root
) {
3278 priv
->previousRequest
= ourRequest
;
3280 iter
= getParentIterator(gIOPowerPlane
);
3283 while ( (next
= iter
->getNextObject()) ) {
3284 if ( (connection
= OSDynamicCast(IOPowerConnection
,next
)) ) {
3285 parent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
3287 if ( parent
->requestPowerDomainState(ourRequest
,connection
,IOPMLowestState
)!= IOPMNoErr
) {
3288 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogRequestDenied
,
3289 (unsigned long)priv
->previousRequest
,0);
3302 //*********************************************************************************
3305 // Call the controlling driver and have it change the power state of the
3306 // hardware. If it returns IOPMAckImplied, the change is complete, and
3307 // we return IOPMAckImplied. Otherwise, it will ack when the change
3308 // is done; we return IOPMWillAckLater.
3309 //*********************************************************************************
3310 IOReturn
IOService::instruct_driver ( unsigned long newState
)
3312 IOReturn return_code
;
3314 if ( pm_vars
->thePowerStates
[newState
].capabilityFlags
& IOPMNotAttainable
) { // can our driver switch to the desired state?
3315 return IOPMAckImplied
; // no, so don't try
3317 priv
->driver_timer
= -1;
3319 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogProgramHardware
,newState
,0);
3321 ioSPMTraceStart(IOPOWER_STATE
, * (int *) this, (int) newState
);
3322 return_code
= pm_vars
->theControllingDriver
->setPowerState( newState
,this ); // yes, instruct it
3323 ioSPMTraceEnd(IOPOWER_STATE
, * (int *) this, (int) newState
, (int) return_code
);
3325 if ( return_code
== IOPMAckImplied
) { // it finished
3326 priv
->driver_timer
= 0;
3327 return IOPMAckImplied
;
3330 if ( priv
->driver_timer
== 0 ) { // it acked behind our back
3331 return IOPMAckImplied
;
3334 if ( return_code
< 0 ) { // somebody goofed
3335 return IOPMAckImplied
;
3337 priv
->driver_timer
= (return_code
* ns_per_us
/ ACK_TIMER_PERIOD
) + 1; // it didn't finish
3338 return IOPMWillAckLater
;
3342 //*********************************************************************************
3345 // We are acquiring the lock we use to protect our queue head from
3346 // simutaneous access by a thread which calls acknowledgePowerStateChange
3347 // or acknowledgeSetPowerState and the ack timer expiration thread.
3348 // Return TRUE if we acquire the lock, and the queue head didn't change
3349 // while we were acquiring the lock (and maybe blocked).
3350 // If there is no queue head, or it changes while we are blocked,
3351 // return FALSE with the lock unlocked.
3352 //*********************************************************************************
3354 bool IOService::acquire_lock ( void )
3356 long current_change_note
;
3358 current_change_note
= priv
->head_note
;
3359 if ( current_change_note
== -1 ) {
3363 IOTakeLock(priv
->our_lock
);
3364 if ( current_change_note
== priv
->head_note
) {
3367 else { // we blocked and something changed radically
3368 IOUnlock(priv
->our_lock
); // so there's nothing to do any more
3374 //*********************************************************************************
3377 // Ask registered applications and kernel clients if we can change to a lower
3380 // Subclass can override this to send a different message type. Parameter is
3381 // the destination state number.
3383 // Return true if we don't have to wait for acknowledgements
3384 //*********************************************************************************
3386 bool IOService::askChangeDown ( unsigned long stateNum
)
3388 return tellClientsWithResponse(kIOMessageCanDevicePowerOff
);
3392 //*********************************************************************************
3395 // Notify registered applications and kernel clients that we are definitely
3398 // Return true if we don't have to wait for acknowledgements
3399 //*********************************************************************************
3401 bool IOService::tellChangeDown1 ( unsigned long stateNum
)
3403 pm_vars
->outofbandparameter
= kNotifyApps
;
3404 return tellChangeDown(stateNum
);
3408 //*********************************************************************************
3411 // Notify priority clients that we are definitely dropping power.
3413 // Return true if we don't have to wait for acknowledgements
3414 //*********************************************************************************
3416 bool IOService::tellChangeDown2 ( unsigned long stateNum
)
3418 pm_vars
->outofbandparameter
= kNotifyPriority
;
3419 return tellChangeDown(stateNum
);
3423 //*********************************************************************************
3426 // Notify registered applications and kernel clients that we are definitely
3429 // Subclass can override this to send a different message type. Parameter is
3430 // the destination state number.
3432 // Return true if we don't have to wait for acknowledgements
3433 //*********************************************************************************
3435 bool IOService::tellChangeDown ( unsigned long stateNum
)
3437 return tellClientsWithResponse(kIOMessageDeviceWillPowerOff
);
3441 //*********************************************************************************
3442 // tellClientsWithResponse
3444 // Notify registered applications and kernel clients that we are definitely
3447 // Return true if we don't have to wait for acknowledgements
3448 //*********************************************************************************
3450 bool IOService::tellClientsWithResponse ( int messageType
)
3452 struct context theContext
;
3453 AbsoluteTime deadline
;
3456 pm_vars
->responseFlags
= OSArray::withCapacity( 1 );
3457 pm_vars
->serialNumber
+= 1;
3459 theContext
.responseFlags
= pm_vars
->responseFlags
;
3460 theContext
.serialNumber
= pm_vars
->serialNumber
;
3461 theContext
.flags_lock
= priv
->flags_lock
;
3462 theContext
.counter
= 1;
3463 theContext
.msgType
= messageType
;
3464 theContext
.us
= this;
3465 theContext
.maxTimeRequested
= 0;
3466 theContext
.stateNumber
= priv
->head_note_state
;
3467 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
3469 IOLockLock(priv
->flags_lock
);
3470 aBool
= OSBoolean::withBoolean(false); // position zero is false to
3471 theContext
.responseFlags
->setObject(0,aBool
); // prevent allowCancelCommon from succeeding
3473 IOLockUnlock(priv
->flags_lock
);
3475 switch ( pm_vars
->outofbandparameter
) {
3477 applyToInterested(gIOAppPowerStateInterest
,tellAppWithResponse
,(void *)&theContext
);
3478 applyToInterested(gIOGeneralInterest
,tellClientWithResponse
,(void *)&theContext
);
3480 case kNotifyPriority
:
3481 applyToInterested(gIOPriorityPowerStateInterest
,tellClientWithResponse
,(void *)&theContext
);
3485 if (! acquire_lock() ) {
3488 IOLockLock(priv
->flags_lock
);
3489 aBool
= OSBoolean::withBoolean(true); // now fix position zero
3490 theContext
.responseFlags
->replaceObject(0,aBool
);
3492 IOLockUnlock(priv
->flags_lock
);
3494 if ( ! checkForDone() ) { // we have to wait for somebody
3495 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogStartAckTimer
,theContext
.maxTimeRequested
,0);
3496 clock_interval_to_deadline(theContext
.maxTimeRequested
/ 1000, kMillisecondScale
, &deadline
);
3498 thread_call_enter_delayed(priv
->ackTimer
, deadline
);
3500 IOUnlock(priv
->our_lock
); // yes
3504 IOUnlock(priv
->our_lock
);
3505 IOLockLock(priv
->flags_lock
);
3506 pm_vars
->responseFlags
->release(); // everybody responded
3507 pm_vars
->responseFlags
= NULL
;
3508 IOLockUnlock(priv
->flags_lock
);
3514 //*********************************************************************************
3515 // tellAppWithResponse
3517 // We send a message to an application, and we expect a response, so we compute a
3518 // cookie we can identify the response with.
3519 //*********************************************************************************
3520 void tellAppWithResponse ( OSObject
* object
, void * context
)
3522 struct context
* theContext
= (struct context
*)context
;
3526 if( OSDynamicCast( IOService
, object
) ) {
3527 IOLockLock(theContext
->flags_lock
);
3528 aBool
= OSBoolean::withBoolean(true);
3529 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3531 IOLockUnlock(theContext
->flags_lock
);
3534 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
3535 IOLockLock(theContext
->flags_lock
);
3536 aBool
= OSBoolean::withBoolean(false);
3537 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3539 IOLockUnlock(theContext
->flags_lock
);
3540 theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)refcon
);
3541 if ( theContext
->maxTimeRequested
< k30seconds
) {
3542 theContext
->maxTimeRequested
= k30seconds
;
3545 theContext
->counter
+= 1;
3549 //*********************************************************************************
3550 // tellClientWithResponse
3552 // We send a message to an in-kernel client, and we expect a response, so we compute a
3553 // cookie we can identify the response with.
3554 // If it doesn't understand the notification (it is not power-management savvy)
3555 // we won't wait for it to prepare for sleep. If it tells us via a return code
3556 // in the passed struct that it is currently ready, we won't wait for it to prepare.
3557 // If it tells us via the return code in the struct that it does need time, we will chill.
3558 //*********************************************************************************
3559 void tellClientWithResponse ( OSObject
* object
, void * context
)
3561 struct context
* theContext
= (struct context
*)context
;
3562 IOPowerStateChangeNotification notify
;
3568 refcon
= ((theContext
->serialNumber
& 0xFFFF)<<16) + (theContext
->counter
& 0xFFFF);
3569 IOLockLock(theContext
->flags_lock
);
3570 aBool
= OSBoolean::withBoolean(false);
3571 theContext
->responseFlags
->setObject(theContext
->counter
,aBool
);
3573 IOLockUnlock(theContext
->flags_lock
);
3575 notify
.powerRef
= (void *)refcon
;
3576 notify
.returnValue
= 0;
3577 notify
.stateNumber
= theContext
->stateNumber
;
3578 notify
.stateFlags
= theContext
->stateFlags
;
3579 retCode
= theContext
->us
->messageClient(theContext
->msgType
,object
,(void *)¬ify
);
3580 if ( retCode
== kIOReturnSuccess
) {
3581 if ( notify
.returnValue
== 0 ) { // client doesn't want time to respond
3582 IOLockLock(theContext
->flags_lock
);
3583 aBool
= OSBoolean::withBoolean(true);
3584 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
); // so set its flag true
3586 IOLockUnlock(theContext
->flags_lock
);
3589 IOLockLock(theContext
->flags_lock
);
3590 theFlag
= theContext
->responseFlags
->getObject(theContext
->counter
); // it does want time, and it hasn't
3591 if ( theFlag
!= 0 ) { // responded yet
3592 if ( ((OSBoolean
*)theFlag
)->isFalse() ) { // so note its time requirement
3593 if ( theContext
->maxTimeRequested
< notify
.returnValue
) {
3594 theContext
->maxTimeRequested
= notify
.returnValue
;
3598 IOLockUnlock(theContext
->flags_lock
);
3601 else { // not a client of ours
3602 IOLockLock(theContext
->flags_lock
);
3603 aBool
= OSBoolean::withBoolean(true); // so we won't be waiting for response
3604 theContext
->responseFlags
->replaceObject(theContext
->counter
,aBool
);
3606 IOLockUnlock(theContext
->flags_lock
);
3608 theContext
->counter
+= 1;
3612 //*********************************************************************************
3615 // Notify registered applications and kernel clients that we are not
3618 // Subclass can override this to send a different message type. Parameter is
3619 // the aborted destination state number.
3620 //*********************************************************************************
3622 void IOService::tellNoChangeDown ( unsigned long )
3624 return tellClients(kIOMessageDeviceWillNotPowerOff
);
3628 //*********************************************************************************
3631 // Notify registered applications and kernel clients that we are raising power.
3633 // Subclass can override this to send a different message type. Parameter is
3634 // the aborted destination state number.
3635 //*********************************************************************************
3637 void IOService::tellChangeUp ( unsigned long )
3639 return tellClients(kIOMessageDeviceHasPoweredOn
);
3643 //*********************************************************************************
3646 // Notify registered applications and kernel clients of something.
3647 //*********************************************************************************
3649 void IOService::tellClients ( int messageType
)
3651 struct context theContext
;
3653 theContext
.msgType
= messageType
;
3654 theContext
.us
= this;
3655 theContext
.stateNumber
= priv
->head_note_state
;
3656 theContext
.stateFlags
= priv
->head_note_capabilityFlags
;
3658 applyToInterested(gIOAppPowerStateInterest
,tellClient
,(void *)&theContext
);
3659 applyToInterested(gIOGeneralInterest
,tellClient
,(void *)&theContext
);
3663 //*********************************************************************************
3666 // Notify a registered application or kernel client of something.
3667 //*********************************************************************************
3668 void tellClient ( OSObject
* object
, void * context
)
3670 struct context
* theContext
= (struct context
*)context
;
3671 IOPowerStateChangeNotification notify
;
3673 notify
.powerRef
= (void *) 0;
3674 notify
.returnValue
= 0;
3675 notify
.stateNumber
= theContext
->stateNumber
;
3676 notify
.stateFlags
= theContext
->stateFlags
;
3678 theContext
->us
->messageClient(theContext
->msgType
,object
, ¬ify
);
3682 // **********************************************************************************
3685 // **********************************************************************************
3686 bool IOService::checkForDone ( void )
3691 IOLockLock(priv
->flags_lock
);
3692 if ( pm_vars
->responseFlags
== NULL
) {
3693 IOLockUnlock(priv
->flags_lock
);
3696 for ( i
= 0; ; i
++ ) {
3697 theFlag
= pm_vars
->responseFlags
->getObject(i
);
3698 if ( theFlag
== NULL
) {
3701 if ( ((OSBoolean
*)theFlag
)->isFalse() ) {
3702 IOLockUnlock(priv
->flags_lock
);
3706 IOLockUnlock(priv
->flags_lock
);
3711 // **********************************************************************************
3714 // **********************************************************************************
3715 bool IOService::responseValid ( unsigned long x
)
3717 UInt16 serialComponent
;
3718 UInt16 ordinalComponent
;
3720 unsigned long refcon
= (unsigned long)x
;
3723 serialComponent
= (refcon
>>16) & 0xFFFF;
3724 ordinalComponent
= refcon
& 0xFFFF;
3726 if ( serialComponent
!= pm_vars
->serialNumber
) {
3730 IOLockLock(priv
->flags_lock
);
3731 if ( pm_vars
->responseFlags
== NULL
) {
3732 IOLockUnlock(priv
->flags_lock
);
3736 theFlag
= pm_vars
->responseFlags
->getObject(ordinalComponent
);
3738 if ( theFlag
== 0 ) {
3739 IOLockUnlock(priv
->flags_lock
);
3743 if ( ((OSBoolean
*)theFlag
)->isFalse() ) {
3744 aBool
= OSBoolean::withBoolean(true);
3745 pm_vars
->responseFlags
->replaceObject(ordinalComponent
,aBool
);
3749 IOLockUnlock(priv
->flags_lock
);
3754 // **********************************************************************************
3757 // Our power state is about to lower, and we have notified applications
3758 // and kernel clients, and one of them has acknowledged. If this is the last to do
3759 // so, and all acknowledgements are positive, we continue with the power change.
3761 // We serialize this processing with timer expiration with a command gate on the
3762 // power management workloop, which the timer expiration is command gated to as well.
3763 // **********************************************************************************
3764 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
3766 if ( ! initialized
) {
3767 return kIOReturnSuccess
; // we're unloading
3770 return pm_vars
->PMcommandGate
->runAction(serializedAllowPowerChange
,(void *)refcon
);
3774 IOReturn
serializedAllowPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
3776 return ((IOService
*)owner
)->serializedAllowPowerChange2((unsigned long)refcon
);
3779 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
3781 if ( ! responseValid(refcon
) ) { // response valid?
3782 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
3783 return kIOReturnSuccess
; // no, just return
3785 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientAcknowledge
,refcon
,0);
3787 return allowCancelCommon();
3791 // **********************************************************************************
3792 // cancelPowerChange
3794 // Our power state is about to lower, and we have notified applications
3795 // and kernel clients, and one of them has vetoed the change. If this is the last
3796 // client to respond, we abandon the power change.
3798 // We serialize this processing with timer expiration with a command gate on the
3799 // power management workloop, which the timer expiration is command gated to as well.
3800 // **********************************************************************************
3801 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
3803 if ( ! initialized
) {
3804 return kIOReturnSuccess
; // we're unloading
3807 return pm_vars
->PMcommandGate
->runAction(serializedCancelPowerChange
,(void *)refcon
);
3811 IOReturn
serializedCancelPowerChange ( OSObject
*owner
, void * refcon
, void *, void *, void *)
3813 return ((IOService
*)owner
)->serializedCancelPowerChange2((unsigned long)refcon
);
3816 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
3818 if ( ! responseValid(refcon
) ) { // response valid?
3819 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogAcknowledgeErr5
,refcon
,0);
3820 return kIOReturnSuccess
; // no, just return
3822 pm_vars
->thePlatform
->PMLog(pm_vars
->ourName
,PMlogClientCancel
,refcon
,0);
3824 pm_vars
->doNotPowerDown
= true;
3826 return allowCancelCommon();
3830 // **********************************************************************************
3831 // allowCancelCommon
3833 // **********************************************************************************
3834 IOReturn
IOService::allowCancelCommon ( void )
3836 if (! acquire_lock() ) {
3837 return kIOReturnSuccess
;
3840 if ( checkForDone() ) { // is this the last response?
3841 stop_ack_timer(); // yes, stop the timer
3842 IOUnlock(priv
->our_lock
);
3843 IOLockLock(priv
->flags_lock
);
3844 if ( pm_vars
->responseFlags
) {
3845 pm_vars
->responseFlags
->release();
3846 pm_vars
->responseFlags
= NULL
;
3848 IOLockUnlock(priv
->flags_lock
);
3849 switch (priv
->machine_state
) {
3850 case IOPMour_prechange_03
: // our change, was it vetoed?
3851 if ( ! pm_vars
->doNotPowerDown
) {
3852 our_prechange_03(); // no, we can continue
3855 tellNoChangeDown(priv
->head_note_state
); // yes, rescind the warning
3856 priv
->head_note_flags
|= IOPMNotDone
; // mark the change note un-actioned
3857 all_done(); // and we're done
3860 case IOPMour_prechange_04
:
3863 case IOPMour_prechange_05
:
3864 our_prechange_05(); // our change, continue
3866 case IOPMparent_down_0
:
3867 parent_down_04(); // parent change, continue
3869 case IOPMparent_down_05
:
3870 parent_down_05(); // parent change, continue
3875 IOUnlock(priv
->our_lock
); // not done yet
3876 return kIOReturnSuccess
;
3880 //*********************************************************************************
3883 // Set to highest available power state for a minimum of duration milliseconds
3884 //*********************************************************************************
3886 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
3888 void IOService::clampPowerOn (unsigned long duration
)
3891 changePowerStateToPriv (pm_vars->theNumberOfPowerStates-1);
3893 if ( priv->clampTimerEventSrc == NULL ) {
3894 priv->clampTimerEventSrc = IOTimerEventSource::timerEventSource(this,
3895 c_PM_Clamp_Timer_Expired);
3897 IOWorkLoop * workLoop = getPMworkloop ();
3899 if ( !priv->clampTimerEventSrc || !workLoop ||
3900 ( workLoop->addEventSource( priv->clampTimerEventSrc) != kIOReturnSuccess) ) {
3905 priv->clampTimerEventSrc->setTimeout(300*USEC_PER_SEC, USEC_PER_SEC);
3909 //*********************************************************************************
3910 // PM_Clamp_Timer_Expired
3912 // called when clamp timer expires...set power state to 0.
3913 //*********************************************************************************
3915 void IOService::PM_Clamp_Timer_Expired (void)
3917 if ( ! initialized
) {
3918 return; // we're unloading
3921 changePowerStateToPriv (0);
3924 //*********************************************************************************
3925 // c_PM_clamp_Timer_Expired (C Func)
3927 // Called when our clamp timer expires...we will call the object method.
3928 //*********************************************************************************
3930 void c_PM_Clamp_Timer_Expired (OSObject
* client
, IOTimerEventSource
*)
3933 ((IOService
*)client
)->PM_Clamp_Timer_Expired ();
3937 //*********************************************************************************
3940 // Does nothing here. This should be implemented in a subclass driver.
3941 //*********************************************************************************
3943 IOReturn
IOService::setPowerState ( unsigned long powerStateOrdinal
, IOService
* whatDevice
)
3949 //*********************************************************************************
3950 // maxCapabilityForDomainState
3952 // Finds the highest power state in the array whose input power
3953 // requirement is equal to the input parameter. Where a more intelligent
3954 // decision is possible, override this in the subclassed driver.
3955 //*********************************************************************************
3957 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
3961 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3964 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3965 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
) {
3973 //*********************************************************************************
3974 // initialPowerStateForDomainState
3976 // Finds the highest power state in the array whose input power
3977 // requirement is equal to the input parameter. Where a more intelligent
3978 // decision is possible, override this in the subclassed driver.
3979 //*********************************************************************************
3981 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
3985 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
3988 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
3989 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
) {
3997 //*********************************************************************************
3998 // powerStateForDomainState
4000 // Finds the highest power state in the array whose input power
4001 // requirement is equal to the input parameter. Where a more intelligent
4002 // decision is possible, override this in the subclassed driver.
4003 //*********************************************************************************
4005 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
4009 if (pm_vars
->theNumberOfPowerStates
== 0 ) {
4012 for ( i
= (pm_vars
->theNumberOfPowerStates
)-1; i
>= 0; i
-- ) {
4013 if ( (domainState
& pm_vars
->thePowerStates
[i
].inputPowerRequirement
) == pm_vars
->thePowerStates
[i
].inputPowerRequirement
) {
4021 //*********************************************************************************
4024 // Does nothing here. This should be implemented in a subclass driver.
4025 //*********************************************************************************
4027 bool IOService::didYouWakeSystem ( void )
4033 //*********************************************************************************
4034 // powerStateWillChangeTo
4036 // Does nothing here. This should be implemented in a subclass driver.
4037 //*********************************************************************************
4039 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
4045 //*********************************************************************************
4046 // powerStateDidChangeTo
4048 // Does nothing here. This should be implemented in a subclass driver.
4049 //*********************************************************************************
4051 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
*)
4057 //*********************************************************************************
4060 // Does nothing here. This should be implemented in a subclass policy-maker.
4061 //*********************************************************************************
4063 void IOService::powerChangeDone ( unsigned long )
4068 //*********************************************************************************
4071 // Does nothing here. This should be implemented in a subclass driver.
4072 //*********************************************************************************
4074 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
4082 #define super OSObject
4084 OSDefineMetaClassAndStructors(IOPMprot
, OSObject
)
4085 //*********************************************************************************
4088 // Serialize protected instance variables for debug output.
4089 //*********************************************************************************
4090 bool IOPMprot::serialize(OSSerialize
*s
) const
4092 OSString
* theOSString
;
4098 buffer
= ptr
= IONew(char, 2000);
4102 ptr
+= sprintf(ptr
,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates
);
4104 if ( theNumberOfPowerStates
!= 0 ) {
4105 ptr
+= sprintf(ptr
,"version %d, ",(unsigned int)thePowerStates
[0].version
);
4108 if ( theNumberOfPowerStates
!= 0 ) {
4109 for ( i
= 0; i
< (int)theNumberOfPowerStates
; i
++ ) {
4110 ptr
+= sprintf(ptr
,"power state %d = { ",i
);
4111 ptr
+= sprintf(ptr
,"capabilityFlags %08x, ",(unsigned int)thePowerStates
[i
].capabilityFlags
);
4112 ptr
+= sprintf(ptr
,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates
[i
].outputPowerCharacter
);
4113 ptr
+= sprintf(ptr
,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates
[i
].inputPowerRequirement
);
4114 ptr
+= sprintf(ptr
,"staticPower %d, ",(unsigned int)thePowerStates
[i
].staticPower
);
4115 ptr
+= sprintf(ptr
,"unbudgetedPower %d, ",(unsigned int)thePowerStates
[i
].unbudgetedPower
);
4116 ptr
+= sprintf(ptr
,"powerToAttain %d, ",(unsigned int)thePowerStates
[i
].powerToAttain
);
4117 ptr
+= sprintf(ptr
,"timeToAttain %d, ",(unsigned int)thePowerStates
[i
].timeToAttain
);
4118 ptr
+= sprintf(ptr
,"settleUpTime %d, ",(unsigned int)thePowerStates
[i
].settleUpTime
);
4119 ptr
+= sprintf(ptr
,"timeToLower %d, ",(unsigned int)thePowerStates
[i
].timeToLower
);
4120 ptr
+= sprintf(ptr
,"settleDownTime %d, ",(unsigned int)thePowerStates
[i
].settleDownTime
);
4121 ptr
+= sprintf(ptr
,"powerDomainBudget %d }, ",(unsigned int)thePowerStates
[i
].powerDomainBudget
);
4125 ptr
+= sprintf(ptr
,"aggressiveness = %d, ",(unsigned int)aggressiveness
);
4126 ptr
+= sprintf(ptr
,"myCurrentState = %d, ",(unsigned int)myCurrentState
);
4127 ptr
+= sprintf(ptr
,"parentsCurrentPowerFlags = %08x, ",(unsigned int)parentsCurrentPowerFlags
);
4128 ptr
+= sprintf(ptr
,"maxCapability = %d }",(unsigned int)maxCapability
);
4130 theOSString
= OSString::withCString(buffer
);
4131 rtn_code
= theOSString
->serialize(s
);
4132 theOSString
->release();
4133 IODelete(buffer
, char, 2000);
4140 #define super OSObject
4142 OSDefineMetaClassAndStructors(IOPMpriv
, OSObject
)
4143 //*********************************************************************************
4146 // Serialize private instance variables for debug output.
4147 //*********************************************************************************
4148 bool IOPMpriv::serialize(OSSerialize
*s
) const
4150 OSString
* theOSString
;
4154 IOPMinformee
* nextObject
;
4156 buffer
= ptr
= IONew(char, 2000);
4160 ptr
+= sprintf(ptr
,"{ this object = %08x",(unsigned int)owner
);
4161 if ( we_are_root
) {
4162 ptr
+= sprintf(ptr
," (root)");
4164 ptr
+= sprintf(ptr
,", ");
4166 nextObject
= interestedDrivers
->firstInList(); // display interested drivers
4167 while ( nextObject
!= NULL
) {
4168 ptr
+= sprintf(ptr
,"interested driver = %08x, ",(unsigned int)nextObject
->whatObject
);
4169 nextObject
= interestedDrivers
->nextInList(nextObject
);
4172 if ( machine_state
!= IOPMfinished
) {
4173 ptr
+= sprintf(ptr
,"machine_state = %d, ",(unsigned int)machine_state
);
4174 ptr
+= sprintf(ptr
,"driver_timer = %d, ",(unsigned int)driver_timer
);
4175 ptr
+= sprintf(ptr
,"settle_time = %d, ",(unsigned int)settle_time
);
4176 ptr
+= sprintf(ptr
,"head_note_flags = %08x, ",(unsigned int)head_note_flags
);
4177 ptr
+= sprintf(ptr
,"head_note_state = %d, ",(unsigned int)head_note_state
);
4178 ptr
+= sprintf(ptr
,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags
);
4179 ptr
+= sprintf(ptr
,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState
);
4180 ptr
+= sprintf(ptr
,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags
);
4181 ptr
+= sprintf(ptr
,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks
);
4184 if ( device_overrides
) {
4185 ptr
+= sprintf(ptr
,"device overrides, ");
4187 ptr
+= sprintf(ptr
,"driverDesire = %d, ",(unsigned int)driverDesire
);
4188 ptr
+= sprintf(ptr
,"deviceDesire = %d, ",(unsigned int)deviceDesire
);
4189 ptr
+= sprintf(ptr
,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState
);
4190 ptr
+= sprintf(ptr
,"previousRequest = %d }",(unsigned int)previousRequest
);
4192 theOSString
= OSString::withCString(buffer
);
4193 rtn_code
= theOSString
->serialize(s
);
4194 theOSString
->release();
4195 IODelete(buffer
, char, 2000);