]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOServicePM.cpp
xnu-344.21.73.tar.gz
[apple/xnu.git] / iokit / Kernel / IOServicePM.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
d7e50217 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
d7e50217
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
d7e50217
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26#include <IOKit/IOService.h>
27#include <IOKit/IOLib.h>
1c79356b
A
28#include <IOKit/IOCommandGate.h>
29#include <IOKit/IOTimerEventSource.h>
30#include <IOKit/IOWorkLoop.h>
31#include <IOKit/IOPlatformExpert.h>
32#include <IOKit/assert.h>
33#include <IOKit/IOMessage.h>
9bccf70c
A
34#include <IOKit/IOKitDebug.h>
35#include <IOKit/IOTimeStamp.h>
1c79356b
A
36#include <IOKit/pwr_mgt/IOPMinformee.h>
37#include "IOKit/pwr_mgt/IOPMinformeeList.h"
38#include "IOKit/pwr_mgt/IOPMchangeNoteList.h"
39#include "IOKit/pwr_mgt/IOPMlog.h"
40#include "IOKit/pwr_mgt/IOPowerConnection.h"
e7c99d92 41#include <kern/clock.h>
1c79356b 42
0b4e3aa0
A
43#define super IORegistryEntry
44
9bccf70c
A
45// Some debug functions
46static inline void
47ioSPMTrace(unsigned int csc,
48 unsigned int a = 0, unsigned int b = 0,
49 unsigned int c = 0, unsigned int d = 0)
50{
51 if (gIOKitDebug & kIOLogTracePower)
52 IOTimeStampConstant(IODBG_POWER(csc), a, b, c, d);
53}
54
55static inline void
56ioSPMTraceStart(unsigned int csc,
57 unsigned int a = 0, unsigned int b = 0,
58 unsigned int c = 0, unsigned int d = 0)
59{
60 if (gIOKitDebug & kIOLogTracePower)
61 IOTimeStampConstant(IODBG_POWER(csc)|DBG_FUNC_START, a, b, c, d);
62}
63
64static inline void
65ioSPMTraceEnd(unsigned int csc,
66 unsigned int a = 0, unsigned int b = 0,
67 unsigned int c = 0, unsigned int d = 0)
68{
69 if (gIOKitDebug & kIOLogTracePower)
70 IOTimeStampConstant(IODBG_POWER(csc)|DBG_FUNC_END, a, b, c, d);
71}
72
73
1c79356b
A
74static void ack_timer_expired(thread_call_param_t);
75static void settle_timer_expired(thread_call_param_t);
9bccf70c 76IOReturn unIdleDevice ( OSObject *, void *, void *, void *, void * );
1c79356b
A
77static void PM_idle_timer_expired(OSObject *, IOTimerEventSource *);
78static void c_PM_Clamp_Timer_Expired (OSObject * client,IOTimerEventSource *);
79void tellAppWithResponse ( OSObject * object, void * context);
80void tellClientWithResponse ( OSObject * object, void * context);
81void tellClient ( OSObject * object, void * context);
82IOReturn serializedAllowPowerChange ( OSObject *, void *, void *, void *, void *);
83IOReturn serializedCancelPowerChange ( OSObject *, void *, void *, void *, void *);
84
85extern const IORegistryPlane * gIOPowerPlane;
86
87
88// and there's 1000 nanoseconds in a microsecond:
89#define ns_per_us 1000
90
91
92// The current change note is processed by a state machine.
93// Inputs are acks from interested parties, ack from the controlling driver,
94// ack timeouts, settle timeout, and powerStateDidChange from the parent.
95// These are the states:
96
97enum {
98 IOPMour_prechange_03 = 1,
0b4e3aa0 99 IOPMour_prechange_04,
1c79356b
A
100 IOPMour_prechange_05,
101 IOPMour_prechange_1,
102 IOPMour_prechange_2,
103 IOPMour_prechange_3,
104 IOPMour_prechange_4,
105 IOPMparent_down_0,
0b4e3aa0 106 IOPMparent_down_05,
1c79356b
A
107 IOPMparent_down_2,
108 IOPMparent_down_3,
109 IOPMparent_down_4,
110 IOPMparent_down_5,
111 IOPMparent_down_6,
112 IOPMparent_up_0,
113 IOPMparent_up_1,
114 IOPMparent_up_4,
115 IOPMparent_up_5,
116 IOPMparent_up_6,
117 IOPMfinished
118 };
119
0b4e3aa0
A
120enum { // values of outofbandparameter
121 kNotifyApps,
122 kNotifyPriority
123};
124
1c79356b
A
125struct context { // used for applyToInterested
126 OSArray * responseFlags;
127 UInt16 serialNumber;
128 UInt16 counter;
129 UInt32 maxTimeRequested;
130 int msgType;
131 IOService * us;
132 IOLock * flags_lock;
0b4e3aa0
A
133 unsigned long stateNumber;
134 IOPMPowerFlags stateFlags;
1c79356b
A
135};
136
137 // five minutes in microseconds
138#define FIVE_MINUTES 5*60*1000000
0b4e3aa0 139#define k30seconds 30*1000000
1c79356b
A
140
141/*
142 There are two different kinds of power state changes. One is initiated by a subclassed device object which has either
143 decided to change power state, or its controlling driver has suggested it, or some other driver wants to use the
144 idle device and has asked it to become usable. The second kind of power state change is initiated by the power
145 domain parent. The two are handled slightly differently.
146
147There is a queue of so-called change notifications, or change notes for short. Usually the queue is empty, and when
148 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
149 at one time, a queue is implemented. Example: the subclass device decides it's idle and initiates a change to a lower
150 power state. This causes interested parties to be notified, but they don't all acknowledge right away. This causes the
151 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
152 wants to raise power back up again. This change can't be started, however, because the previous one isn't complete yet,
153 so the second one waits in the queue. During this time, the parent decides to lower or raise the power state of the entire
154 power domain and notifies the device, and that notification goes into the queue, too, and can't be actioned until the
155 others are.
156
157 This is how a power change initiated by the subclass device is handled:
158 First, all interested parties are notified of the change via their powerStateWillChangeTo method. If they all don't
159 acknowledge via return code, then we have to wait. If they do, or when they finally all acknowledge via our
160 acknowledgePowerChange method, then we can continue. We call the controlling driver, instructing it to change to
161 the new state. Then we wait for power to settle. If there is no settling-time, or after it has passed, we notify
162 interested parties again, this time via their powerStateDidChangeTo methods. When they have all acked, we're done.
163 If we lowered power and don't need the power domain to be in its current power state, we suggest to the parent that
164 it lower the power domain state.
165
166 This is how a change to a lower power domain state initiated by the parent is handled:
167 First, we figure out what power state we will be in when the new domain state is reached. Then all interested parties are
168 notified that we are moving to that new state. When they have acknowledged, we call the controlling driver to assume
169 that state and we wait for power to settle. Then we acknowledge our preparedness to our parent. When all its interested
170 parties have acknowledged, it lowers power and then notifies its interested parties again. When we get this call, we notify
171 our interested parties that the power state has changed, and when they have all acknowledged, we're done.
172
173 This is how a change to a higher power domain state initiated by the parent is handled:
174 We figure out what power state we will be in when the new domain state is reached. If it is different from our current
175 state we acknowledge the parent. When all the parent's interested parties have acknowledged, it raises power in the
176domain and waits for power to settle. Then it notifies everyone that the new state has been reached. When we get this call,
177 we call the controlling driver, instructing it to assume the new state, and wait for power to settle. Then we notify our interested
178 parties. When they all acknowledge we are done.
179
180 In either of the two cases above, it is possible that we will not be changing state even though the domain is. Examples:
181 A change to a lower domain state may not affect us because we are already in a low enough state, and
182 We will not take advantage of a change to a higher domain state, because we have no need of the higher power.
183 In such a case, there is nothing to do but acknowledge the parent. So when the parent calls our powerDomainWillChange
184 method, and we decide that we will not be changing state, we merely acknowledge the parent, via return code, and wait.
185 When the parent subsequently calls powerStateDidChange, we acknowledge again via return code, and the change is complete.
186
187 Power state changes are processed in a state machine, and since there are four varieties of power state changes, there are
188 four major paths through the state machine:
189
190 The fourth is nearly trivial. In this path, the parent is changing the domain state, but we are not changing the device state.
191 The change starts when the parent calls powerDomainWillChange. All we do is acknowledge the parent.
192When the parent calls powerStateDidChange, we acknowledge the parent again, and we're done.
193
194 The first is fairly simple. It starts when a power domain child calls requestPowerDomainState and we decide to change power states
195 to accomodate the child, or if our power-controlling driver calls changePowerStateTo, or if some other driver which is using our
196 device calls makeUsable, or if a subclassed object calls changePowerStateToPriv. These are all power changes initiated by us, not
197 forced upon us by the parent. We start by notifying interested parties. If they all acknowledge via return code, we can go
198 on to state "our_prechange_1". Otherwise, we start the ack timer and wait for the stragglers to acknowlege by calling
199 acknowledgePowerChange. We move on to state "our_prechange_1" when all the stragglers have acknowledged,
200 or when the ack timer expires on all those which didn't acknowledge. In "our_prechange_1" we call the power-controlling
201 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".
202 Otherwise, we have to wait for it, so we set the ack timer and wait. When it calls acknowledgeSetPowerState, or when the
203 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
204 when changing from our current state to the new state. If not, we go right away to "our_prechange_3". Otherwise, we
205 set the settle timer and wait. When it expires, we move on. In "our_prechange_3" state, we notify all our interested parties
206 via their powerStateDidChange methods that we have finished changing power state. If they all acknowledge via return
207 code, we move on to "our_prechange_4". Otherwise we set the ack timer and wait. When they have all acknowledged, or
208 when the ack timer has expired for those that didn't, we move on to "our_prechange_4", where we remove the used
209 change note from the head of the queue and start the next one if one exists.
210
211 Parent-initiated changes are more complex in the state machine. First, power going up and power going down are handled
212 differently, so they have different paths throught the state machine. Second, we can acknowledge the parent's notification
213 in two different ways, so each of the parent paths is really two.
214
215 When the parent calls our powerDomainWillChange method, notifying us that it will lower power in the domain, we decide
216 what state that will put our device in. Then we embark on the state machine path "IOPMparent_down_1"
217 and "IOPMparent_down_2", in which we notify interested parties of the upcoming change, instruct our driver to make
218 the change, check for settle time, and notify interested parties of the completed change. If we get to the end of this path without
219 stalling due to an interested party which didn't acknowledge via return code, due to the controlling driver not able to change
220 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.
221 If we do stall in any of those states, we return IOPMWillAckLater to the parent and enter the parallel path "IOPMparent_down_4"
222 "IOPMparent_down_5", and "IOPMparent_down_3", where we continue with the same processing, except that at the end we
223 acknowledge the parent explicitly via acknowledgePowerChange, and we're done with the change.
224Then when the parent calls us at powerStateDidChange we acknowledging via return code, because we have already made
225 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.
226
227 The case of the parent raising power in the domain is handled similarly in that there are parallel paths, one for no-stall
228 that ends in implicit acknowleging the parent, and one that has stalled at least once that ends in explicit acknowledging
229 the parent. This case is different, though in that our device changes state in the second half, after the parent calls
230 powerStateDidChange rather than before, as in the power-lowering case.
231
232 When the parent calls our powerDomainWillChange method, notifying us that it will raise power in the domain, we acknowledge
233 via return code, because there's really nothing we can do until the power is actually raised in the domain.
234 When the parent calls us at powerStateDidChange, we start by notifying our interested parties. If they all acknowledge via return code,
235 we go on to" IOPMparent_up_1" to instruct the driver to raise its power level. After that, we check for any
236 necessary settling time in "IOPMparent_up_2", and we notify all interested parties that power has changed
237 in "IOPMparent_up_3". If none of these operations stall, we acknowledge the parent via return code, release
238 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",
239 "IOPMparent_up_4", "IOPMparent_up_5", and "IOPMparent_up_6", which ends with
240 our explicit acknowledgement to the parent.
241
242*/
243
244
245const char priv_key[ ] = "Power Management private data";
246const char prot_key[ ] = "Power Management protected data";
247
248
249void IOService::PMinit ( void )
250{
251 if ( ! initialized ) {
252
253 pm_vars = new IOPMprot; // make space for our variables
254 priv = new IOPMpriv;
255 pm_vars->init();
256 priv->init();
257
258 setProperty(prot_key, (OSObject *) pm_vars); // add these to the properties
259 setProperty(priv_key, (OSObject *) priv);
260
261 priv->owner = this;
262 pm_vars->theNumberOfPowerStates = 0; // then initialize them
263 priv->we_are_root = false;
264 pm_vars->theControllingDriver = NULL;
265 priv->our_lock = IOLockAlloc();
266 priv->flags_lock = IOLockAlloc();
0b4e3aa0
A
267 priv->queue_lock = IOLockAlloc();
268 pm_vars->childLock = IOLockAlloc();
269 pm_vars->parentLock = IOLockAlloc();
1c79356b
A
270 priv->interestedDrivers = new IOPMinformeeList;
271 priv->interestedDrivers->initialize();
272 priv->changeList = new IOPMchangeNoteList;
273 priv->changeList->initialize();
274 pm_vars->aggressiveness = 0;
275 for (unsigned int i = 0; i <= kMaxType; i++) {
276 pm_vars->current_aggressiveness_values[i] = 0;
277 pm_vars->current_aggressiveness_valid[i] = false;
278 }
279 pm_vars->myCurrentState = 0;
280 priv->imminentState = 0;
1c79356b
A
281 priv->ourDesiredPowerState = 0;
282 pm_vars->parentsCurrentPowerFlags = 0;
283 pm_vars->maxCapability = 0;
284 priv->driverDesire = 0;
285 priv->deviceDesire = 0;
286 priv->initial_change = true;
287 priv->need_to_become_usable = false;
288 priv->previousRequest = 0;
289 priv->device_overrides = false;
290 priv->machine_state = IOPMfinished;
1c79356b
A
291 priv->timerEventSrc = NULL;
292 priv->clampTimerEventSrc = NULL;
293 pm_vars->PMworkloop = NULL;
294 priv->activityLock = NULL;
295 pm_vars->ourName = getName();
296 pm_vars->thePlatform = getPlatform();
297 pm_vars->parentsKnowState = false;
298 assert( pm_vars->thePlatform != 0 );
299 priv->clampOn = false;
300 pm_vars->serialNumber = 0;
301 pm_vars->responseFlags = NULL;
302 pm_vars->doNotPowerDown = true;
303 pm_vars->PMcommandGate = NULL;
304 priv->ackTimer = thread_call_allocate((thread_call_func_t)ack_timer_expired, (thread_call_param_t)this);
305 priv->settleTimer = thread_call_allocate((thread_call_func_t)settle_timer_expired, (thread_call_param_t)this);
306 initialized = true;
307 }
308}
309
310
0b4e3aa0
A
311//*********************************************************************************
312// PMfree
313//
314// Free up the data created in PMinit, if it exists.
315//*********************************************************************************
316void IOService::PMfree ( void )
317{
318 if ( priv ) {
319 if ( priv->clampTimerEventSrc != NULL ) {
320 getPMworkloop()->removeEventSource(priv->clampTimerEventSrc);
321 priv->clampTimerEventSrc->release();
322 priv->clampTimerEventSrc = NULL;
323 }
324 if ( priv->timerEventSrc != NULL ) {
325 pm_vars->PMworkloop->removeEventSource(priv->timerEventSrc);
326 priv->timerEventSrc->release();
327 priv->timerEventSrc = NULL;
328 }
329 if ( priv->settleTimer ) {
330 thread_call_cancel(priv->settleTimer);
331 thread_call_free(priv->settleTimer);
332 priv->settleTimer = NULL;
333 }
334 if ( priv->ackTimer ) {
335 thread_call_cancel(priv->ackTimer);
336 thread_call_free(priv->ackTimer);
337 priv->ackTimer = NULL;
338 }
339 if ( priv->our_lock ) {
340 IOLockFree(priv->our_lock);
341 priv->our_lock = NULL;
342 }
343 if ( priv->flags_lock ) {
344 IOLockFree(priv->flags_lock);
345 priv->flags_lock = NULL;
346 }
347 if ( priv->activityLock ) {
348 IOLockFree(priv->activityLock);
349 priv->activityLock = NULL;
350 }
351 priv->interestedDrivers->release();
352 priv->changeList->release();
353 priv->release(); // remove instance variables
354 }
355
356 if ( pm_vars ) {
0b4e3aa0
A
357 if ( pm_vars->PMcommandGate ) {
358 pm_vars->PMcommandGate->release();
359 pm_vars->PMcommandGate = NULL;
360 }
361 if ( pm_vars->PMworkloop ) {
362 // The work loop object returned from getPMworkLoop() is
363 // never retained, therefore it should not be released.
364 // pm_vars->PMworkloop->release();
365 pm_vars->PMworkloop = NULL;
366 }
367 if ( pm_vars->responseFlags ) {
368 pm_vars->responseFlags->release();
369 pm_vars->responseFlags = NULL;
370 }
371 pm_vars->release(); // remove instance variables
372 }
373}
374
375
1c79356b
A
376//*********************************************************************************
377// PMstop
378//
0b4e3aa0 379// Disconnect the node from its parents and children in the Power Plane.
1c79356b
A
380//*********************************************************************************
381void IOService::PMstop ( void )
382{
383 OSIterator * iter;
384 OSObject * next;
385 IOPowerConnection * connection;
0b4e3aa0
A
386 IOService * theChild;
387 IOService * theParent;
1c79356b
A
388
389 removeProperty(prot_key); // remove the properties
390 removeProperty(priv_key);
391
392 iter = getParentIterator(gIOPowerPlane); // detach parents
393
394 if ( iter ) {
395 while ( (next = iter->getNextObject()) ) {
396 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
0b4e3aa0
A
397 theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
398 if ( theParent ) {
399 theParent->removePowerChild(connection);
400 theParent->release();
401 }
1c79356b
A
402 }
403 }
404 iter->release();
405 }
406 detachAbove( gIOPowerPlane ); // detach IOConnections
407
408 pm_vars->parentsKnowState = false; // no more power state changes
1c79356b
A
409
410 iter = getChildIterator(gIOPowerPlane); // detach children
411
412 if ( iter ) {
413 while ( (next = iter->getNextObject()) ) {
414 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
0b4e3aa0
A
415 theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
416 if ( theChild ) {
417 connection->detachFromChild(theChild,gIOPowerPlane); // detach nub from child
418 theChild->release();
419 }
420 detachFromChild(connection,gIOPowerPlane); // detach us from nub
1c79356b
A
421 }
422 }
423 iter->release();
424 }
1c79356b 425
0b4e3aa0
A
426 // Remove all interested drivers from the list, including the power
427 // controlling driver.
428 //
429 // Usually, the controlling driver and the policy-maker functionality
430 // are implemented by the same object, and without the deregistration,
431 // the object will be holding an extra retain on itself, and cannot
432 // be freed.
433
434 if ( priv && priv->interestedDrivers )
435 {
436 IOPMinformee * informee;
1c79356b 437
0b4e3aa0
A
438 while (( informee = priv->interestedDrivers->firstInList() ))
439 deRegisterInterestedDriver( informee->whatObject );
440 }
1c79356b
A
441}
442
443
444//*********************************************************************************
445// joinPMtree
446//
447// A policy-maker calls its nub here when initializing, to be attached into
448// the power management hierarchy. The default function is to call the
449// platform expert, which knows how to do it. This method is overridden
450// by a nub subclass which may either know how to do it, or may need
451// to take other action.
452//
453// This may be the only "power management" method used in a nub,
454// meaning it may not be initialized for power management.
455//*********************************************************************************
456void IOService::joinPMtree ( IOService * driver )
457{
458 IOPlatformExpert * thePlatform;
459
460 thePlatform = getPlatform();
461 assert(thePlatform != 0 );
462 thePlatform->PMRegisterDevice(this,driver);
463}
464
465
466//*********************************************************************************
467// youAreRoot
468//
469// Power Managment is informing us that we are the root power domain.
470// The only difference between us and any other power domain is that
471// we have no parent and therefore never call it.
472//*********************************************************************************
473IOReturn IOService::youAreRoot ( void )
474{
475 priv-> we_are_root = true;
476 pm_vars->parentsKnowState = true;
477 attachToParent( getRegistryRoot(),gIOPowerPlane );
478
479 return IOPMNoErr;
480}
481
482
483//*********************************************************************************
484// setPowerParent
485//
486// Power Management is informing us who our parent is.
487// If we have a controlling driver, find out, given our newly-informed
488// power domain state, what state it would be in, and then tell it
489// to assume that state.
490//*********************************************************************************
491IOReturn IOService::setPowerParent ( IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags currentState )
492{
493 OSIterator * iter;
494 OSObject * next;
495 IOPowerConnection * connection;
496 unsigned long tempDesire;
497
498 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetParent,stateKnown,currentState);
499
0b4e3aa0
A
500 IOLockLock(pm_vars->parentLock);
501
1c79356b
A
502 if ( stateKnown && ((pm_vars->PMworkloop == NULL) || (pm_vars->PMcommandGate == NULL)) ) {
503 getPMworkloop(); // we have a path to the root
504 if ( pm_vars->PMworkloop != NULL ) { // find out the workloop
505 if ( pm_vars->PMcommandGate == NULL ) { // and make our command gate
506 pm_vars->PMcommandGate = IOCommandGate::commandGate((OSObject *)this);
507 if ( pm_vars->PMcommandGate != NULL ) {
508 pm_vars->PMworkloop->addEventSource(pm_vars->PMcommandGate);
509 }
510 }
511 }
512 }
513
0b4e3aa0
A
514 IOLockUnlock(pm_vars->parentLock);
515
1c79356b
A
516 theParent->setParentCurrentPowerFlags(currentState); // set our connection data
517 theParent->setParentKnowsState(stateKnown);
518
519 pm_vars->parentsKnowState = true; // combine parent knowledge
520 pm_vars->parentsCurrentPowerFlags = 0;
521
522 iter = getParentIterator(gIOPowerPlane);
523
524 if ( iter ) {
525 while ( (next = iter->getNextObject()) ) {
526 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
527 pm_vars->parentsKnowState &= connection->parentKnowsState();
528 pm_vars->parentsCurrentPowerFlags |= connection->parentCurrentPowerFlags();
529 }
530 }
531 iter->release();
532 }
533
534 if ( (pm_vars->theControllingDriver != NULL) &&
535 (pm_vars->parentsKnowState) ) {
536 pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentsCurrentPowerFlags);
537 tempDesire = priv->deviceDesire; // initially change into the state we are already in
538 priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
0b4e3aa0
A
539 computeDesiredState();
540 priv->previousRequest = 0xffffffff;
1c79356b
A
541 changeState();
542 priv->deviceDesire = tempDesire; // put this back like before
543 }
0b4e3aa0 544
1c79356b
A
545 return IOPMNoErr;
546}
547
548
549//*********************************************************************************
550// addPowerChild
551//
552// Power Management is informing us who our children are.
553//*********************************************************************************
554IOReturn IOService::addPowerChild ( IOService * theChild )
555{
556 IOPowerConnection * connection;
557 unsigned int i;
558
559 if ( ! initialized ) {
560 return IOPMNotYetInitialized; // we're not a power-managed IOService
561 }
562
563 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAddChild,0,0);
564
565 connection = new IOPowerConnection; // make a nub
566
567 connection->init();
568 connection->start(this);
0b4e3aa0 569 connection->setAwaitingAck(false);
1c79356b
A
570
571 attachToChild( connection,gIOPowerPlane ); // connect it up
572 connection->attachToChild( theChild,gIOPowerPlane );
573 connection->release();
574
575 if ( (pm_vars->theControllingDriver == NULL) || // tell it the current state of the power domain
576 ! (inPlane(gIOPowerPlane)) ||
577 ! (pm_vars->parentsKnowState) ) {
578 theChild->setPowerParent(connection,false,0);
579 if ( inPlane(gIOPowerPlane) ) {
580 for (i = 0; i <= kMaxType; i++) {
581 if ( pm_vars->current_aggressiveness_valid[i] ) {
582 theChild->setAggressiveness (i, pm_vars->current_aggressiveness_values[i]);
583 }
584 }
585 }
586 }
587 else {
588 theChild->setPowerParent(connection,true,pm_vars->thePowerStates[pm_vars->myCurrentState].outputPowerCharacter);
589 for (i = 0; i <= kMaxType; i++) {
590 if ( pm_vars->current_aggressiveness_valid[i] ) {
591 theChild->setAggressiveness (i, pm_vars->current_aggressiveness_values[i]);
592 }
593 }
594 add_child_to_active_change(connection); // catch it up if change is in progress
595 }
596
597 return IOPMNoErr;
598}
599
600
601//*********************************************************************************
602// removePowerChild
603//
604//*********************************************************************************
0b4e3aa0
A
605IOReturn IOService::removePowerChild ( IOPowerConnection * theNub )
606{
607 IORegistryEntry * theChild;
608
1c79356b
A
609 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveChild,0,0);
610
0b4e3aa0
A
611 theNub->retain();
612
613 theChild = theNub->copyChildEntry(gIOPowerPlane); // detach nub from child
614 if ( theChild ) {
615 theNub->detachFromChild(theChild, gIOPowerPlane);
616 theChild->release();
617 }
618 detachFromChild(theNub,gIOPowerPlane); // detach from the nub
619
620 if ( theNub->getAwaitingAck() ) { // are we awaiting an ack from this child?
621 theNub->setAwaitingAck(false); // yes, pretend we got one
622 if ( acquire_lock() ) {
623 if (priv->head_note_pendingAcks != 0 ) {
624 priv->head_note_pendingAcks -= 1; // that's one fewer ack to worry about
625 if ( priv->head_note_pendingAcks == 0 ) { // is that the last?
626 stop_ack_timer(); // yes, stop the timer
627 IOUnlock(priv->our_lock);
628 all_acked(); // and now we can continue our power change
629 }
630 else {
631 IOUnlock(priv->our_lock);
632 }
633 }
634 else {
635 IOUnlock(priv->our_lock);
636 }
637 }
638 }
d7e50217 639
0b4e3aa0 640 theNub->release();
1c79356b
A
641
642 if ( (pm_vars->theControllingDriver == NULL) || // if not fully initialized
643 ! (inPlane(gIOPowerPlane)) ||
644 ! (pm_vars->parentsKnowState) ) {
645 return IOPMNoErr; // we can do no more
646 }
647
d7e50217
A
648 // Perhaps the departing child was holding up idle or system sleep - we need to re-evaluate our
649 // childrens' requests. Clear and re-calculate our kIOPMChildClamp and kIOPMChildClamp2 bits.
650 rebuildChildClampBits();
651
0b4e3aa0 652 computeDesiredState(); // this may be different now
1c79356b
A
653 changeState(); // change state if we can now tolerate lower power
654
655 return IOPMNoErr;
656}
657
658
659//*********************************************************************************
660// registerPowerDriver
661//
662// A driver has called us volunteering to control power to our device.
663// If the power state array it provides is richer than the one we already
664// know about (supplied by an earlier volunteer), then accept the offer.
665// Notify all interested parties of our power state, which we now know.
666//*********************************************************************************
667
668IOReturn IOService::registerPowerDriver ( IOService * controllingDriver, IOPMPowerState* powerStates, unsigned long numberOfStates )
669{
670 unsigned long i;
671 unsigned long tempDesire;
672
673 if ( (numberOfStates > pm_vars->theNumberOfPowerStates) && (numberOfStates > 1) ) {
674 if ( priv->changeList->currentChange() == -1 ) {
675 if ( controllingDriver != NULL ) {
676 if ( numberOfStates <= IOPMMaxPowerStates ) {
677 switch ( powerStates[0].version ) {
678 case 1:
679 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver,
680 (unsigned long)numberOfStates, (unsigned long)powerStates[0].version);
681 for ( i = 0; i < numberOfStates; i++ ) {
682 pm_vars->thePowerStates[i] = powerStates[i];
683 }
684 break;
685 case 2:
686 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriver,
687 (unsigned long) numberOfStates,(unsigned long) powerStates[0].version);
688 for ( i = 0; i < numberOfStates; i++ ) {
689 pm_vars->thePowerStates[i].version = powerStates[i].version;
690 pm_vars->thePowerStates[i].capabilityFlags = powerStates[i].capabilityFlags;
691 pm_vars->thePowerStates[i].outputPowerCharacter = powerStates[i].outputPowerCharacter;
692 pm_vars->thePowerStates[i].inputPowerRequirement = powerStates[i].inputPowerRequirement;
693 pm_vars->thePowerStates[i].staticPower = powerStates[i].staticPower;
694 pm_vars->thePowerStates[i].unbudgetedPower = powerStates[i].unbudgetedPower;
695 pm_vars->thePowerStates[i].powerToAttain = powerStates[i].powerToAttain;
696 pm_vars->thePowerStates[i].timeToAttain = powerStates[i].timeToAttain;
697 pm_vars->thePowerStates[i].settleUpTime = powerStates[i].settleUpTime;
698 pm_vars->thePowerStates[i].timeToLower = powerStates[i].timeToLower;
699 pm_vars->thePowerStates[i].settleDownTime = powerStates[i].settleDownTime;
700 pm_vars->thePowerStates[i].powerDomainBudget = powerStates[i].powerDomainBudget;
701 }
702 break;
703 default:
704 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr1,
705 (unsigned long)powerStates[0].version,0);
706 return IOPMNoErr;
707 }
708
709 pm_vars->myCharacterFlags = 0; // make a mask of all the character bits we know about
710 for ( i = 0; i < numberOfStates; i++ ) {
711 pm_vars->myCharacterFlags |= pm_vars->thePowerStates[i].outputPowerCharacter;
712 }
713
714 pm_vars->theNumberOfPowerStates = numberOfStates;
715 pm_vars->theControllingDriver = controllingDriver;
716 if ( priv->interestedDrivers->findItem(controllingDriver) == NULL ) { // register it as interested
717 registerInterestedDriver (controllingDriver ); // unless already done
718 }
719 if ( priv->need_to_become_usable ) {
720 priv->need_to_become_usable = false;
721 priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1;
722 }
723
724 if ( inPlane(gIOPowerPlane) &&
725 (pm_vars->parentsKnowState) ) {
726 pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentsCurrentPowerFlags);
727 tempDesire = priv->deviceDesire; // initially change into the state we are already in
728 priv->deviceDesire = pm_vars->theControllingDriver->initialPowerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
0b4e3aa0 729 computeDesiredState();
1c79356b
A
730 changeState();
731 priv->deviceDesire = tempDesire; // put this back like before
732 }
733 }
734 else {
735 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr2,(unsigned long)numberOfStates,0);
736 }
737 }
738 else {
739 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr4,0,0);
740 }
741 }
742 }
743 else {
744 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogControllingDriverErr5,(unsigned long)numberOfStates,0);
745 }
746 return IOPMNoErr;
747}
748
749//*********************************************************************************
750// registerInterestedDriver
751//
752// Add the caller to our list of interested drivers and return our current
753// power state. If we don't have a power-controlling driver yet, we will
754// call this interested driver again later when we do get a driver and find
755// out what the current power state of the device is.
756//*********************************************************************************
757
758IOPMPowerFlags IOService::registerInterestedDriver ( IOService * theDriver )
759{
760 IOPMinformee * newInformee;
761 IOPMPowerFlags futureCapability;
762
763 if (theDriver == NULL ) {
764 return 0;
765 }
766
767 newInformee = new IOPMinformee; // make new driver node
768 newInformee->initialize(theDriver);
769 priv->interestedDrivers->addToList(newInformee); // add it to list of drivers
770
771 if ( (pm_vars->theControllingDriver == NULL) ||
772 ! (inPlane(gIOPowerPlane)) ||
773 ! (pm_vars->parentsKnowState) ) {
774 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,IOPMNotPowerManaged,0);
775 return IOPMNotPowerManaged; // can't tell it a state yet
776 }
777
778 switch (priv->machine_state) { // can we notify new driver of a change in progress?
779 case IOPMour_prechange_1:
780 case IOPMour_prechange_4:
781 case IOPMparent_down_4:
782 case IOPMparent_down_6:
783 case IOPMparent_up_0:
784 case IOPMparent_up_6:
785 futureCapability = priv->head_note_capabilityFlags; // yes, remember what we tell it
786 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,(unsigned long)futureCapability,1);
787 add_driver_to_active_change(newInformee); // notify it
788 return futureCapability; // and return the same thing
789 }
790
791 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInterestedDriver,
792 (unsigned long) pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags,2);
793 return pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags; // no, return current capability
794}
795
796
797//*********************************************************************************
798// deRegisterInterestedDriver
799//
800//*********************************************************************************
801IOReturn IOService::deRegisterInterestedDriver ( IOService * theDriver )
802{
803 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRemoveDriver,0,0);
804
805 priv->interestedDrivers->removeFromList(theDriver); // remove the departing driver
806
807 return IOPMNoErr;
808}
809
810
811//*********************************************************************************
812// acknowledgePowerChange
813//
814// After we notified one of the interested drivers or a power-domain child
815// of an impending change in power, it has called to say it is now
816// prepared for the change. If this object is the last to
817// acknowledge this change, we take whatever action we have been waiting
818// for.
819// That may include acknowledging to our parent. In this case, we do it
820// last of all to insure that this doesn't cause the parent to call us some-
821// where else and alter data we are relying on here (like the very existance
822// of a "current change note".)
823//*********************************************************************************
824
825IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
826{
827 IOPMinformee * ackingObject;
0b4e3aa0
A
828 unsigned long childPower = kIOPMUnknown;
829 IOService * theChild;
1c79356b
A
830
831 ackingObject = priv->interestedDrivers->findItem(whichObject); // one of our interested drivers?
832 if ( ackingObject == NULL ) {
833 if ( ! isChild(whichObject,gIOPowerPlane) ) {
834 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr1,0,0);
835 kprintf("errant driver: %s\n",whichObject->getName());
836 return IOPMNoErr; // no, just return
837 }
838 else {
0b4e3aa0 839 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChildAcknowledge,priv->head_note_pendingAcks,0);
1c79356b
A
840 }
841 }
842 else {
0b4e3aa0 843 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDriverAcknowledge,priv->head_note_pendingAcks,0);
1c79356b
A
844 }
845
846 if (! acquire_lock() ) {
847 return IOPMNoErr;
848 }
849
850 if (priv->head_note_pendingAcks != 0 ) { // yes, make sure we're expecting acks
851 if ( ackingObject != NULL ) { // it's an interested driver
852 if ( ackingObject->timer != 0 ) { // make sure we're expecting this ack
853 ackingObject->timer = 0; // mark it acked
0b4e3aa0
A
854 priv->head_note_pendingAcks -= 1; // that's one fewer to worry about
855 if ( priv->head_note_pendingAcks == 0 ) { // is that the last?
856 stop_ack_timer(); // yes, stop the timer
1c79356b
A
857 IOUnlock(priv->our_lock);
858 all_acked(); // and now we can continue
859 return IOPMNoErr;
860 }
861 }
862 else {
863 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr2,0,0); // this driver has already acked
864 kprintf("errant driver: %s\n",whichObject->getName());
865 }
866 }
867 else { // it's a child
0b4e3aa0
A
868 if ( ((IOPowerConnection *)whichObject)->getAwaitingAck() ) { // make sure we're expecting this ack
869 priv->head_note_pendingAcks -= 1; // that's one fewer to worry about
870 ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
871 theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
872 if ( theChild ) {
873 childPower = theChild->currentPowerConsumption();
874 theChild->release();
875 }
876 if ( childPower == kIOPMUnknown ) {
877 pm_vars->thePowerStates[priv->head_note_state].staticPower = kIOPMUnknown;
878 }
879 else {
880 if ( pm_vars->thePowerStates[priv->head_note_state].staticPower != kIOPMUnknown ) {
881 pm_vars->thePowerStates[priv->head_note_state].staticPower += childPower;
882 }
883 }
884 if ( priv->head_note_pendingAcks == 0 ) { // is that the last?
885 stop_ack_timer(); // yes, stop the timer
886 IOUnlock(priv->our_lock);
887 all_acked(); // and now we can continue
888 return IOPMNoErr;
889 }
890 }
891 }
1c79356b
A
892 }
893 else {
894 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr3,0,0); // not expecting anybody to ack
895 kprintf("errant driver: %s\n",whichObject->getName());
896 }
897 IOUnlock(priv->our_lock);
898 return IOPMNoErr;
899}
900
901//*********************************************************************************
902// acknowledgeSetPowerState
903//
904// After we instructed our controlling driver to change power states,
905// it has called to say it has finished doing so.
906// We continue to process the power state change.
907//*********************************************************************************
908
909IOReturn IOService::acknowledgeSetPowerState ( void )
910{
911 if (! acquire_lock() ) {
912 return IOPMNoErr;
913 }
9bccf70c
A
914
915 ioSPMTrace(IOPOWER_ACK, * (int *) this);
916
1c79356b
A
917 if ( priv->driver_timer == -1 ) {
918 priv->driver_timer = 0; // driver is acking instead of using return code
919 }
920 else {
921 if ( priv->driver_timer > 0 ) { // are we expecting this?
922 stop_ack_timer(); // yes, stop the timer
923 priv->driver_timer = 0;
924 IOUnlock(priv->our_lock);
925 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDriverAcknowledgeSet,0,0);
926 driver_acked();
927 return IOPMNoErr;
928 }
929 else {
930 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr4,0,0); // no
931 }
932 }
933 IOUnlock(priv->our_lock);
934 return IOPMNoErr;
935}
936
937
938//*********************************************************************************
939// driver_acked
940//
941// Either the controlling driver has called acknowledgeSetPowerState
942// or the acknowledgement timer has expired while waiting for that.
943// We carry on processing the current change note.
944//*********************************************************************************
945
946void IOService::driver_acked ( void )
947{
948 switch (priv->machine_state) {
949 case IOPMour_prechange_2:
950 our_prechange_2();
951 break;
952 case IOPMparent_down_5:
953 parent_down_5();
954 break;
955 case IOPMparent_up_4:
956 parent_up_4();
957 break;
958 }
959}
960
961
962//*********************************************************************************
963// powerDomainWillChangeTo
964//
965// Called by the power-hierarchy parent notifying of a new power state
966// in the power domain.
967// We enqueue a parent power-change to our queue of power changes.
968// This may or may not cause us to change power, depending on what
969// kind of change is occuring in the domain.
970//*********************************************************************************
971
972IOReturn IOService::powerDomainWillChangeTo ( IOPMPowerFlags newPowerStateFlags, IOPowerConnection * whichParent )
973{
974 OSIterator * iter;
975 OSObject * next;
976 IOPowerConnection * connection;
977 unsigned long newStateNumber;
978 IOPMPowerFlags combinedPowerFlags;
979
980 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogWillChange,(unsigned long)newPowerStateFlags,0);
981
982 if ( ! inPlane(gIOPowerPlane) ) {
983 return IOPMAckImplied; // somebody goofed
984 }
985
0b4e3aa0
A
986 IOLockLock(pm_vars->parentLock);
987
1c79356b
A
988 if ( (pm_vars->PMworkloop == NULL) || (pm_vars->PMcommandGate == NULL) ) {
989 getPMworkloop(); // we have a path to the root,
990 if ( pm_vars->PMworkloop != NULL ) { // so find out the workloop
991 if ( pm_vars->PMcommandGate == NULL ) { // and make our command gate
992 pm_vars->PMcommandGate = IOCommandGate::commandGate((OSObject *)this);
993 if ( pm_vars->PMcommandGate != NULL ) {
994 pm_vars->PMworkloop->addEventSource(pm_vars->PMcommandGate);
995 }
996 }
997 }
998 }
999
0b4e3aa0
A
1000 IOLockUnlock(pm_vars->parentLock);
1001
1c79356b
A
1002 combinedPowerFlags = 0; // combine parents' power states
1003
1004 iter = getParentIterator(gIOPowerPlane);
1005
1006 if ( iter ) {
1007 while ( (next = iter->getNextObject()) ) {
1008 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
1009 if ( connection == whichParent ){
1010 combinedPowerFlags |= newPowerStateFlags;
1011 }
1012 else {
1013 combinedPowerFlags |= connection->parentCurrentPowerFlags();
1014 }
1015 }
1016 }
1017 iter->release();
1018 }
0b4e3aa0 1019
1c79356b
A
1020 if ( pm_vars->theControllingDriver == NULL ) { // we can't take any more action
1021 return IOPMAckImplied;
1022 }
1023 newStateNumber = pm_vars->theControllingDriver->maxCapabilityForDomainState(combinedPowerFlags);
0b4e3aa0
A
1024 return enqueuePowerChange(IOPMParentInitiated | IOPMDomainWillChange,
1025 newStateNumber,combinedPowerFlags,whichParent,newPowerStateFlags); //make the change
1c79356b
A
1026}
1027
1028
1029//*********************************************************************************
1030// powerDomainDidChangeTo
1031//
1032// Called by the power-hierarchy parent after the power state of the power domain
1033// has settled at a new level.
1034// We enqueue a parent power-change to our queue of power changes.
1035// This may or may not cause us to change power, depending on what
1036// kind of change is occuring in the domain.
1037//*********************************************************************************
1038
1039IOReturn IOService::powerDomainDidChangeTo ( IOPMPowerFlags newPowerStateFlags, IOPowerConnection * whichParent )
1040{
0b4e3aa0 1041 unsigned long newStateNumber;
1c79356b
A
1042
1043 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogDidChange,newPowerStateFlags,0);
1044
0b4e3aa0
A
1045 setParentInfo(newPowerStateFlags,whichParent);
1046
1047 if ( pm_vars->theControllingDriver == NULL ) {
1048 return IOPMAckImplied;
1049 }
1050
1051 newStateNumber = pm_vars->theControllingDriver->maxCapabilityForDomainState(pm_vars->parentsCurrentPowerFlags);
1052 return enqueuePowerChange(IOPMParentInitiated | IOPMDomainDidChange,
1053 newStateNumber,pm_vars->parentsCurrentPowerFlags,whichParent,0); // tell interested parties about it
1054}
1055
1056
1057//*********************************************************************************
1058// setParentInfo
1059//
1060// Set our connection data for one specific parent, and then combine all the parent
1061// data together.
1062//*********************************************************************************
1063
1064void IOService::setParentInfo ( IOPMPowerFlags newPowerStateFlags, IOPowerConnection * whichParent )
1065{
1066 OSIterator * iter;
1067 OSObject * next;
1068 IOPowerConnection * connection;
1069
1c79356b
A
1070 whichParent->setParentCurrentPowerFlags(newPowerStateFlags); // set our connection data
1071 whichParent->setParentKnowsState(true);
1072
0b4e3aa0
A
1073 IOLockLock(pm_vars->parentLock);
1074
1c79356b
A
1075 pm_vars->parentsCurrentPowerFlags = 0; // recompute our parent info
1076 pm_vars->parentsKnowState = true;
1077
1078 iter = getParentIterator(gIOPowerPlane);
1079
1080 if ( iter ) {
1081 while ( (next = iter->getNextObject()) ) {
1082 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
1083 pm_vars->parentsKnowState &= connection->parentKnowsState();
1084 pm_vars->parentsCurrentPowerFlags |= connection->parentCurrentPowerFlags();
1085 }
1086 }
1087 iter->release();
1088 }
0b4e3aa0 1089 IOLockUnlock(pm_vars->parentLock);
1c79356b
A
1090}
1091
d7e50217
A
1092//*********************************************************************************
1093// rebuildChildClampBits
1094//
1095// The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1096// indicate that one of our children (or grandchildren or great-grandchildren or ...)
1097// doesn't support idle or system sleep in its current state. Since we don't track the
1098// origin of each bit, every time any child changes state we have to clear these bits
1099// and rebuild them.
1100//*********************************************************************************
1101
1102void IOService::rebuildChildClampBits(void)
1103{
1104 unsigned long i;
1105 OSIterator * iter;
1106 OSObject * next;
1107 IOPowerConnection * connection;
1108
1109
1110 // A child's desires has changed. We need to rebuild the child-clamp bits in our
1111 // power state array. Start by clearing the bits in each power state.
1112
1113 for ( i = 0; i < pm_vars->theNumberOfPowerStates; i++ ) {
1114 pm_vars->thePowerStates[i].capabilityFlags &= ~(kIOPMChildClamp | kIOPMChildClamp2);
1115 }
1116
1117 // Now loop through the children. When we encounter the calling child, save
1118 // the computed state as this child's desire. And while we're at it, set the ChildClamp bits
1119 // in any of our states that some child has requested with clamp on.
1120
1121 iter = getChildIterator(gIOPowerPlane);
1122
1123 if ( iter )
1124 {
1125 while ( (next = iter->getNextObject()) )
1126 {
1127 if ( (connection = OSDynamicCast(IOPowerConnection,next)) )
1128 {
1129 if ( connection->getPreventIdleSleepFlag() )
1130 pm_vars->thePowerStates[connection->getDesiredDomainState()].capabilityFlags |= kIOPMChildClamp;
1131 if ( connection->getPreventSystemSleepFlag() )
1132 pm_vars->thePowerStates[connection->getDesiredDomainState()].capabilityFlags |= kIOPMChildClamp2;
1133 }
1134 }
1135 iter->release();
1136 }
1137
1138}
1139
1c79356b
A
1140
1141//*********************************************************************************
1142// requestPowerDomainState
1143//
0b4e3aa0
A
1144// The kIOPMPreventIdleSleep and/or kIOPMPreventIdleSleep bits may be be set in the parameter.
1145// It is not considered part of the state specification.
1c79356b
A
1146//*********************************************************************************
1147IOReturn IOService::requestPowerDomainState ( IOPMPowerFlags desiredState, IOPowerConnection * whichChild, unsigned long specification )
1148{
1149 unsigned long i;
0b4e3aa0
A
1150 unsigned long computedState;
1151 unsigned long theDesiredState = desiredState & ~(kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
1c79356b
A
1152 OSIterator * iter;
1153 OSObject * next;
1154 IOPowerConnection * connection;
1155
1156 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDomain,
1157 (unsigned long)desiredState,(unsigned long)specification);
1158
1159 if ( pm_vars->theControllingDriver == NULL) {
1160 return IOPMNotYetInitialized;
1161 }
1162
1163 switch (specification) {
1164 case IOPMLowestState:
1165 i = 0;
1166 while ( i < pm_vars->theNumberOfPowerStates ) {
0b4e3aa0 1167 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & theDesiredState) == (theDesiredState & pm_vars->myCharacterFlags) ) {
1c79356b
A
1168 break;
1169 }
1170 i++;
1171 }
1172 if ( i >= pm_vars->theNumberOfPowerStates ) {
1173 return IOPMNoSuchState;
1174 }
1175 break;
1176
1177 case IOPMNextLowerState:
1178 i = pm_vars->myCurrentState - 1;
1179 while ( i >= 0 ) {
0b4e3aa0 1180 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & theDesiredState) == (theDesiredState & pm_vars->myCharacterFlags) ) {
1c79356b
A
1181 break;
1182 }
1183 i--;
1184 }
1185 if ( i < 0 ) {
1186 return IOPMNoSuchState;
1187 }
1188 break;
1189
1190 case IOPMHighestState:
1191 i = pm_vars->theNumberOfPowerStates;
1192 while ( i >= 0 ) {
1193 i--;
0b4e3aa0 1194 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & theDesiredState) == (theDesiredState & pm_vars->myCharacterFlags) ) {
1c79356b
A
1195 break;
1196 }
1197 }
1198 if ( i < 0 ) {
1199 return IOPMNoSuchState;
1200 }
1201 break;
1202
1203 case IOPMNextHigherState:
1204 i = pm_vars->myCurrentState + 1;
1205 while ( i < pm_vars->theNumberOfPowerStates ) {
0b4e3aa0 1206 if ( ( pm_vars->thePowerStates[i].outputPowerCharacter & theDesiredState) == (theDesiredState & pm_vars->myCharacterFlags) ) {
1c79356b
A
1207 break;
1208 }
1209 i++;
1210 }
1211 if ( i == pm_vars->theNumberOfPowerStates ) {
1212 return IOPMNoSuchState;
1213 }
1214 break;
1215
1216 default:
1217 return IOPMBadSpecification;
1218 }
1219
0b4e3aa0
A
1220 computedState = i;
1221
1222 IOLockLock(pm_vars->childLock);
1223
d7e50217
A
1224 // Now loop through the children. When we encounter the calling child, save
1225 // the computed state as this child's desire.
1c79356b
A
1226 iter = getChildIterator(gIOPowerPlane);
1227
1228 if ( iter ) {
1229 while ( (next = iter->getNextObject()) ) {
1230 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
1231 if ( connection == whichChild ) {
0b4e3aa0
A
1232 connection->setDesiredDomainState(computedState);
1233 connection->setPreventIdleSleepFlag(desiredState & kIOPMPreventIdleSleep);
1234 connection->setPreventSystemSleepFlag(desiredState & kIOPMPreventSystemSleep);
1235 connection->setChildHasRequestedPower();
1236 }
1c79356b
A
1237 }
1238 }
1239 iter->release();
1240 }
d7e50217
A
1241
1242 // Since a child's power requirements may have changed, clear and rebuild
1243 // kIOPMChildClamp and kIOPMChildClamp2 (idle and system sleep clamps)
1244 rebuildChildClampBits();
0b4e3aa0
A
1245
1246 IOLockUnlock(pm_vars->childLock);
1247
1248 computeDesiredState(); // this may be different now
1c79356b
A
1249
1250 if ( inPlane(gIOPowerPlane) &&
1251 (pm_vars->parentsKnowState) ) {
1252 changeState(); // change state if all children can now tolerate lower power
1253 }
1254
1255 if ( priv->clampOn ) { // are we clamped on, waiting for this child?
1256 priv->clampOn = false; // yes, remove the clamp
1257 changePowerStateToPriv(0);
1258 }
1259
1260 return IOPMNoErr;
1261}
1262
1263
1264//*********************************************************************************
1265// temporaryPowerClampOn
1266//
1267// A power domain wants to clamp its power on till it has children which
1268// will thendetermine the power domain state.
1269//
1270// We enter the highest state until addPowerChild is called.
1271//*********************************************************************************
1272
1273IOReturn IOService::temporaryPowerClampOn ( void )
1274{
1275 priv->clampOn = true;
1276 makeUsable();
1277 return IOPMNoErr;
1278}
1279
1280
1281//*********************************************************************************
1282// makeUsable
1283//
1284// Some client of our device is asking that we become usable. Although
1285// this has not come from a subclassed device object, treat it exactly
1286// as if it had. In this way, subsequent requests for lower power from
1287// a subclassed device object will pre-empt this request.
1288//
1289// We treat this as a subclass object request to switch to the
1290// highest power state.
1291//*********************************************************************************
1292
1293IOReturn IOService::makeUsable ( void )
1294{
1295 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogMakeUsable,0,0);
1296
1297 if ( pm_vars->theControllingDriver == NULL ) {
1298 priv->need_to_become_usable = true;
1299 return IOPMNoErr;
1300 }
1301 priv->deviceDesire = pm_vars->theNumberOfPowerStates - 1;
0b4e3aa0 1302 computeDesiredState();
1c79356b
A
1303 if ( inPlane(gIOPowerPlane) && (pm_vars->parentsKnowState) ) {
1304 return changeState();
1305 }
1306 return IOPMNoErr;
1307}
1308
1309
1310//*********************************************************************************
1311// currentCapability
1312//
1313//*********************************************************************************
1314
1315IOPMPowerFlags IOService::currentCapability ( void )
1316{
1317 if ( pm_vars->theControllingDriver == NULL ) {
1318 return 0;
1319 }
1320 else {
1321 return pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags;
1322 }
1323}
1324
1325
1326//*********************************************************************************
1327// changePowerStateTo
1328//
1329// For some reason, our power-controlling driver has decided it needs to change
1330// power state. We enqueue the power change so that appropriate parties
1331// will be notified, and then we will instruct the driver to make the change.
1332//*********************************************************************************
1333
1334IOReturn IOService::changePowerStateTo ( unsigned long ordinal )
1335{
1336 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateTo,ordinal,0);
1337
1338 if ( ordinal >= pm_vars->theNumberOfPowerStates ) {
1339 return IOPMParameterError;
1340 }
1341 priv->driverDesire = ordinal;
0b4e3aa0 1342 computeDesiredState();
1c79356b
A
1343 if ( inPlane(gIOPowerPlane) && (pm_vars->parentsKnowState) ) {
1344 return changeState();
1345 }
1346
1347 return IOPMNoErr;
1348}
1349
1350//*********************************************************************************
1351// changePowerStateToPriv
1352//
1353// For some reason, a subclassed device object has decided it needs to change
1354// power state. We enqueue the power change so that appropriate parties
1355// will be notified, and then we will instruct the driver to make the change.
1356//*********************************************************************************
1357
1358IOReturn IOService::changePowerStateToPriv ( unsigned long ordinal )
1359{
1360 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeStateToPriv,ordinal,0);
1361
1362 if ( pm_vars->theControllingDriver == NULL) {
1363 return IOPMNotYetInitialized;
1364 }
1365 if ( ordinal >= pm_vars->theNumberOfPowerStates ) {
1366 return IOPMParameterError;
1367 }
1368 priv->deviceDesire = ordinal;
0b4e3aa0 1369 computeDesiredState();
1c79356b
A
1370 if ( inPlane(gIOPowerPlane) && (pm_vars->parentsKnowState) ) {
1371 return changeState();
1372 }
1373
1374 return IOPMNoErr;
1375}
1376
1377
1378//*********************************************************************************
0b4e3aa0 1379// computeDesiredState
1c79356b 1380//
1c79356b
A
1381//*********************************************************************************
1382
0b4e3aa0 1383void IOService::computeDesiredState ( void )
1c79356b
A
1384{
1385 OSIterator * iter;
1386 OSObject * next;
1387 IOPowerConnection * connection;
1388 unsigned long newDesiredState = 0;
1389
1390 // Compute the maximum of our children's desires, our controlling driver's desire, and the subclass device's desire.
1391
1392 if ( ! priv->device_overrides ) {
1393 iter = getChildIterator(gIOPowerPlane);
1394
1395 if ( iter ) {
1396 while ( (next = iter->getNextObject()) ) {
1397 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
1398 if ( connection->getDesiredDomainState() > newDesiredState ) {
1399 newDesiredState = connection->getDesiredDomainState();
1400 }
1401 }
1402 }
1403 iter->release();
1404 }
1405
1406 if ( priv->driverDesire > newDesiredState ) {
1407 newDesiredState = priv->driverDesire;
1408 }
1409 }
1410
1411 if ( priv->deviceDesire > newDesiredState ) {
1412 newDesiredState = priv->deviceDesire;
1413 }
1414
1415 priv->ourDesiredPowerState = newDesiredState;
0b4e3aa0
A
1416}
1417
1c79356b 1418
0b4e3aa0
A
1419//*********************************************************************************
1420// changeState
1421//
1422// A subclass object, our controlling driver, or a power domain child
1423// has asked for a different power state. Here we compute what new
1424// state we should enter and enqueue the change (or start it).
1425//*********************************************************************************
1426
1427IOReturn IOService::changeState ( void )
1428{
1c79356b
A
1429 if ( (pm_vars->theControllingDriver == NULL) || // if not fully initialized
1430 ! (inPlane(gIOPowerPlane)) ||
1431 ! (pm_vars->parentsKnowState) ) {
1432 return IOPMNoErr; // we can do no more
1433 }
1434
0b4e3aa0 1435 return enqueuePowerChange(IOPMWeInitiated,priv->ourDesiredPowerState,0,0,0);
1c79356b
A
1436}
1437
1438
1439//*********************************************************************************
1440// currentPowerConsumption
1441//
1442//*********************************************************************************
1443
1444unsigned long IOService::currentPowerConsumption ( void )
1445{
1446 if ( pm_vars->theControllingDriver == NULL ) {
0b4e3aa0 1447 return kIOPMUnknown;
1c79356b 1448 }
0b4e3aa0 1449 if ( pm_vars->thePowerStates[pm_vars->myCurrentState].capabilityFlags & kIOPMStaticPowerValid ) {
1c79356b
A
1450 return pm_vars->thePowerStates[pm_vars->myCurrentState].staticPower;
1451 }
0b4e3aa0 1452 return kIOPMUnknown;
1c79356b
A
1453}
1454
1455//*********************************************************************************
1456// activityTickle
1457//
1458// The activity tickle with parameter kIOPMSubclassPolicyis not handled
1459// here and should have been intercepted by the subclass.
1460// The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
1461// flag to be set, and the device state checked. If the device has been
1462// powered down, it is powered up again.
1463//*********************************************************************************
1464
1465bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber=0 )
1466{
e7c99d92
A
1467 AbsoluteTime uptime;
1468
1c79356b
A
1469 if ( type == kIOPMSuperclassPolicy1 ) {
1470 if ( (priv->activityLock == NULL) ||
9bccf70c 1471 (pm_vars->theControllingDriver == NULL) ) {
1c79356b
A
1472 return true;
1473 }
1474 IOTakeLock(priv->activityLock);
1475 priv->device_active = true;
e7c99d92
A
1476
1477 clock_get_uptime(&uptime);
1478 priv->device_active_timestamp = uptime;
1479
1c79356b
A
1480 if ( pm_vars->myCurrentState >= stateNumber) {
1481 IOUnlock(priv->activityLock);
1482 return true;
1483 }
9bccf70c
A
1484 IOUnlock(priv->activityLock);
1485 pm_vars->PMcommandGate->runAction(unIdleDevice,(void *)stateNumber);
1c79356b
A
1486 return false;
1487 }
1488 return true;
1489}
1490
1491//*********************************************************************************
1492// getPMworkloop
1493//
1494// A child is calling to get a pointer to the Power Management workloop.
1495// We got it or get it from one of our parents.
1496//*********************************************************************************
1497
1498IOWorkLoop * IOService::getPMworkloop ( void )
1499{
0b4e3aa0
A
1500IOService * nub;
1501IOService * parent;
1c79356b
A
1502
1503 if ( ! inPlane(gIOPowerPlane) ) {
1504 return NULL;
1505 }
1506 if ( pm_vars->PMworkloop == NULL ) { // we have no workloop yet
0b4e3aa0
A
1507 nub = (IOService *)copyParentEntry(gIOPowerPlane);
1508 if ( nub ) {
1509 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
1510 nub->release();
1511 if ( parent ) { // ask one of our parents for the workloop
1512 pm_vars->PMworkloop = parent->getPMworkloop();
1513 parent->release();
1514 }
1c79356b
A
1515 }
1516 }
1517 return pm_vars->PMworkloop;
1518}
1519
1520
1521//*********************************************************************************
1522// setIdleTimerPeriod
1523//
1524// A subclass policy-maker is going to use our standard idleness
1525// detection service. Make a command queue and an idle timer and
1526// connect them to the power management workloop. Finally,
1527// start the timer.
1528//*********************************************************************************
1529
1530IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
1531{
1532 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMsetIdleTimerPeriod,period, 0);
1533
1534 priv->idle_timer_period = period;
1535
1536 if ( period > 0 ) {
1537 if ( getPMworkloop() == NULL ) {
1538 return kIOReturnError;
1539 }
1c79356b
A
1540 // make the timer event
1541 if ( priv->timerEventSrc == NULL ) {
1542 priv->timerEventSrc = IOTimerEventSource::timerEventSource(this,
1543 PM_idle_timer_expired);
1544 if ( ! priv->timerEventSrc ||
1545 ( pm_vars->PMworkloop->addEventSource( priv->timerEventSrc) != kIOReturnSuccess) ) {
1546 return kIOReturnError;
1547 }
1548 }
1549
1550 if ( priv->activityLock == NULL ) {
1551 priv->activityLock = IOLockAlloc();
1552 }
1553
1554 start_PM_idle_timer();
1555 }
1556 return IOPMNoErr;
1557}
1558
1559
1560//*********************************************************************************
1561// start_PM_idle_timer
1562//
1563// The parameter is a pointer to us. Use it to call our timeout method.
1564//*********************************************************************************
1565void IOService::start_PM_idle_timer ( void )
1566{
e7c99d92
A
1567 AbsoluteTime uptime;
1568 AbsoluteTime delta;
1569 UInt64 delta_ns;
1570 UInt64 delta_secs;
1571 UInt64 delay_secs;
1572
1573 IOLockLock(priv->activityLock);
1574
1575 clock_get_uptime(&uptime);
1576
1577 /* Calculate time difference using funky macro from clock.h.
1578 */
1579 delta = uptime;
1580 SUB_ABSOLUTETIME(&delta, &(priv->device_active_timestamp));
1581
1582 /* Figure it in seconds.
1583 */
1584 absolutetime_to_nanoseconds(delta, &delta_ns);
1585 delta_secs = delta_ns / NSEC_PER_SEC;
1586
1587 /* Be paranoid about delta somehow exceeding timer period.
1588 */
1589 if (delta_secs < priv->idle_timer_period ) {
1590 delay_secs = priv->idle_timer_period - delta_secs;
1591 } else {
1592 delay_secs = priv->idle_timer_period;
1593 }
1594
1595 priv->timerEventSrc->setTimeout(delay_secs, NSEC_PER_SEC);
1596
1597 IOLockUnlock(priv->activityLock);
1598 return;
1c79356b
A
1599}
1600
1601
1602//*********************************************************************************
1603// PM_idle_timer_expired
1604//
1605// The parameter is a pointer to us. Use it to call our timeout method.
1606//*********************************************************************************
1607
1608void PM_idle_timer_expired(OSObject * ourSelves, IOTimerEventSource *)
1609{
1610 ((IOService *)ourSelves)->PM_idle_timer_expiration();
1611}
1612
1613
1614//*********************************************************************************
1615// PM_idle_timer_expiration
1616//
1617// The idle timer has expired. If there has been activity since the last
1618// expiration, just restart the timer and return. If there has not been
1619// activity, switch to the next lower power state and restart the timer.
1620//*********************************************************************************
1621
1622void IOService::PM_idle_timer_expiration ( void )
1623{
1624 if ( ! initialized ) {
1625 return; // we're unloading
1626 }
1627
1628 if ( priv->idle_timer_period > 0 ) {
1629 IOTakeLock(priv->activityLock);
1630 if ( priv->device_active ) {
1631 priv->device_active = false;
1632 IOUnlock(priv->activityLock);
1633 start_PM_idle_timer();
1634 return;
1635 }
1636 if ( pm_vars->myCurrentState > 0 ) {
1637 IOUnlock(priv->activityLock);
1c79356b
A
1638 changePowerStateToPriv(pm_vars->myCurrentState - 1);
1639 start_PM_idle_timer();
1640 return;
1641 }
1642 IOUnlock(priv->activityLock);
1643 start_PM_idle_timer();
1644 }
1645}
1646
1647
1648
1649// **********************************************************************************
9bccf70c 1650// unIdleDevice
1c79356b 1651//
9bccf70c 1652// We are behind the command gate. This serializes with respect to timer expiration.
1c79356b 1653// **********************************************************************************
9bccf70c 1654IOReturn unIdleDevice ( OSObject * theDriver, void * param1, void * param2, void * param3, void * param4 )
1c79356b 1655{
9bccf70c
A
1656 ((IOService *)theDriver)->command_received(param1,param2,param3,param4);
1657 return kIOReturnSuccess;
1c79356b
A
1658}
1659
1660
1661// **********************************************************************************
1662// command_received
1663//
9bccf70c 1664// We are un-idling a device due to its activity tickle.
1c79356b 1665// **********************************************************************************
9bccf70c 1666void IOService::command_received ( void * stateNumber, void *, void * , void * )
1c79356b
A
1667{
1668 if ( ! initialized ) {
1669 return; // we're unloading
1670 }
1671
9bccf70c
A
1672 if ( (pm_vars->myCurrentState < (unsigned long)stateNumber) &&
1673 (priv->imminentState < (unsigned long)stateNumber) ) {
1674 changePowerStateToPriv((unsigned long)stateNumber);
1c79356b
A
1675 }
1676}
1677
1678
1679//*********************************************************************************
1680// setAggressiveness
1681//
1682// Pass on the input parameters to all power domain children. All those which are
1683// power domains will pass it on to their children, etc.
1684//*********************************************************************************
1685
1686IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
1687{
0b4e3aa0
A
1688 OSIterator * iter;
1689 OSObject * next;
1c79356b 1690 IOPowerConnection * connection;
0b4e3aa0 1691 IOService * child;
1c79356b
A
1692
1693 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSetAggressiveness,type, newLevel);
1694
1695 if ( type <= kMaxType ) {
1696 pm_vars->current_aggressiveness_values[type] = newLevel;
1697 pm_vars->current_aggressiveness_valid[type] = true;
1698 }
1699
1700 iter = getChildIterator(gIOPowerPlane);
1701
1702 if ( iter ) {
1703 while ( (next = iter->getNextObject()) ) {
1704 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
0b4e3aa0
A
1705 child = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
1706 if ( child ) {
1707 child->setAggressiveness(type, newLevel);
1708 child->release();
1709 }
1c79356b
A
1710 }
1711 }
1712 iter->release();
1713 }
1714
1715 return IOPMNoErr;
1716}
1717
1718//*********************************************************************************
1719// getAggressiveness
1720//
1721// Called by the user client.
1722//*********************************************************************************
1723
1724IOReturn IOService::getAggressiveness ( unsigned long type, unsigned long * currentLevel )
1725{
1726 if ( type <= kMaxType ) {
1727 *currentLevel = pm_vars->current_aggressiveness_values[type];
1728 }
1729 return kIOReturnSuccess;
1730}
1731
1732//*********************************************************************************
1733// systemWake
1734//
1735// Pass this to all power domain children. All those which are
1736// power domains will pass it on to their children, etc.
1737//*********************************************************************************
1738
1739IOReturn IOService::systemWake ( void )
1740{
0b4e3aa0
A
1741 OSIterator * iter;
1742 OSObject * next;
1c79356b 1743 IOPowerConnection * connection;
0b4e3aa0 1744 IOService * theChild;
1c79356b
A
1745
1746 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogSystemWake,0, 0);
1747
1748 iter = getChildIterator(gIOPowerPlane);
1749
1750 if ( iter ) {
1751 while ( (next = iter->getNextObject()) ) {
1752 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
0b4e3aa0
A
1753 theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
1754 if ( theChild ) {
1755 theChild->systemWake();
1756 theChild->release();
1757 }
1c79356b
A
1758 }
1759 }
1760 iter->release();
1761 }
1762
1763 if ( pm_vars->theControllingDriver != NULL ) {
1764 if ( pm_vars->theControllingDriver->didYouWakeSystem() ) {
1765 makeUsable();
1766 }
1767 }
1768
1769 return IOPMNoErr;
1770}
1771
1772
1773//*********************************************************************************
1774// temperatureCriticalForZone
1775//
1776//*********************************************************************************
1777
1778IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
1779{
0b4e3aa0
A
1780 IOService * theParent;
1781 IOService * theNub;
1782
1c79356b
A
1783 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCriticalTemp,0,0);
1784
1785 if ( inPlane(gIOPowerPlane) && ! (priv->we_are_root) ) {
0b4e3aa0
A
1786 theNub = (IOService *)copyParentEntry(gIOPowerPlane);
1787 if ( theNub ) {
1788 theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
1789 theNub->release();
1790 if ( theParent ) {
1791 theParent->temperatureCriticalForZone(whichZone);
1792 theParent->release();
1793 }
1794 }
1c79356b
A
1795 }
1796 return IOPMNoErr;
1797}
1798
1799
1800//*********************************************************************************
1801// powerOverrideOnPriv
1802//
1803//*********************************************************************************
1804
1805
1806IOReturn IOService::powerOverrideOnPriv ( void )
1807{
1808 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOn,0,0);
1809
1810 priv->device_overrides = true; // turn on the override
0b4e3aa0 1811 computeDesiredState();
1c79356b
A
1812 return changeState(); // change state if that changed something
1813}
1814
1815
1816//*********************************************************************************
1817// powerOverrideOffPriv
1818//
1819//*********************************************************************************
1820IOReturn IOService::powerOverrideOffPriv ( void )
1821{
1822 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogOverrideOff,0,0);
1823
1824 priv->device_overrides = false; // turn off the override
0b4e3aa0
A
1825 computeDesiredState();
1826 if( priv->clampOn)
1827 return makeUsable();
1828 else
1829 return changeState(); // change state if that changed something
1c79356b
A
1830}
1831
1832
1833//*********************************************************************************
1834// enqueuePowerChange
1835//
1836// Allocate a new state change notification, initialize it with fields from the
1837// caller, and add it to the tail of the list of pending power changes.
1838//
1839// If it is early enough in the list, and almost all the time it is the only one in
1840// the list, start the power change.
1841//
1842// In rare instances, this change will preempt the previous change in the list.
1843// If the previous change is un-actioned in any way (because we are still
1844// processing an even earlier power change), and if both the previous change
1845// in the list and this change are initiated by us (not the parent), then we
1846// needn't perform the previous change, so we collapse the list a little.
1847//*********************************************************************************
1848
0b4e3aa0 1849IOReturn IOService::enqueuePowerChange ( unsigned long flags, unsigned long whatStateOrdinal, unsigned long domainState, IOPowerConnection * whichParent, unsigned long singleParentState )
1c79356b
A
1850{
1851 long newNote;
1852 long previousNote;
1853
1854// Create and initialize the new change note
1855
0b4e3aa0 1856 IOLockLock(priv->queue_lock);
1c79356b
A
1857 newNote = priv->changeList->createChangeNote();
1858 if ( newNote == -1 ) {
0b4e3aa0 1859 IOLockUnlock(priv->queue_lock);
1c79356b
A
1860 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogEnqueueErr,0,0);
1861 return IOPMAckImplied; // uh-oh, our list is full
1862 }
1863
1864 priv->changeList->changeNote[newNote].newStateNumber = whatStateOrdinal;
1865 priv->changeList->changeNote[newNote].outputPowerCharacter = pm_vars->thePowerStates[whatStateOrdinal].outputPowerCharacter;
1866 priv->changeList->changeNote[newNote].inputPowerRequirement = pm_vars->thePowerStates[whatStateOrdinal].inputPowerRequirement;
1867 priv->changeList->changeNote[newNote].capabilityFlags = pm_vars->thePowerStates[whatStateOrdinal].capabilityFlags;
1868 priv->changeList->changeNote[newNote].flags = flags;
1869 if (flags & IOPMParentInitiated ) {
1870 priv->changeList->changeNote[newNote].domainState = domainState;
1871 priv->changeList->changeNote[newNote].parent = whichParent;
0b4e3aa0
A
1872 whichParent->retain();
1873 priv->changeList->changeNote[newNote].singleParentState = singleParentState;
1c79356b
A
1874 }
1875
1876 previousNote = priv->changeList->previousChangeNote(newNote);
1877
1878 if ( previousNote == -1 ) {
1879
1880 // Queue is empty, we can start this change.
1881
1882 if (flags & IOPMWeInitiated ) {
0b4e3aa0 1883 IOLockUnlock(priv->queue_lock);
1c79356b
A
1884 start_our_change(newNote);
1885 return 0;
1886 }
1887 else {
0b4e3aa0 1888 IOLockUnlock(priv->queue_lock);
1c79356b
A
1889 return start_parent_change(newNote);
1890 }
1891 }
1892
1893 // The queue is not empty. Try to collapse this new change and the previous one in queue into one change.
1894 // This is possible only if both changes are initiated by us, and neither has been started yet.
1895 // Do this more than once if possible.
1896
1897 // (A change is started iff it is at the head of the queue)
1898
1899 while ( (previousNote != priv->head_note) && (previousNote != -1) &&
1900 (priv->changeList->changeNote[newNote].flags & priv->changeList->changeNote[previousNote].flags & IOPMWeInitiated) ) {
1901 priv->changeList->changeNote[previousNote].outputPowerCharacter = priv->changeList->changeNote[newNote].outputPowerCharacter;
1902 priv->changeList->changeNote[previousNote].inputPowerRequirement = priv->changeList->changeNote[newNote].inputPowerRequirement;
1903 priv->changeList->changeNote[previousNote].capabilityFlags =priv-> changeList->changeNote[newNote].capabilityFlags;
0b4e3aa0
A
1904 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCollapseQueue,priv->changeList->changeNote[newNote].newStateNumber,
1905 priv->changeList->changeNote[previousNote].newStateNumber);
1c79356b
A
1906 priv->changeList->changeNote[previousNote].newStateNumber = priv->changeList->changeNote[newNote].newStateNumber;
1907 priv->changeList->releaseTailChangeNote();
1908 newNote = previousNote;
1909 previousNote = priv->changeList->previousChangeNote(newNote);
1c79356b 1910 }
0b4e3aa0 1911 IOLockUnlock(priv->queue_lock);
1c79356b
A
1912 return IOPMWillAckLater; // in any case, we can't start yet
1913}
1914
1c79356b
A
1915//*********************************************************************************
1916// notifyAll
1917//
1918// Notify all interested parties either that a change is impending or that the
1919// previously-notified change is done and power has settled.
1920// The parameter identifies whether this is the
1921// pre-change notification or the post-change notification.
1922//
1923//*********************************************************************************
1924
1925IOReturn IOService::notifyAll ( bool is_prechange )
1926{
1927 IOPMinformee * nextObject;
1928 OSIterator * iter;
1929 OSObject * next;
1930 IOPowerConnection * connection;
1931
1932 // To prevent acknowledgePowerChange from finishing the change note and removing it from the queue if
1933 // some driver calls it, we inflate the number of pending acks so it cannot become zero. We'll fix it later.
1934
1935 priv->head_note_pendingAcks =1;
1936
1937 // OK, we will go through the lists of interested drivers and power domain children
1938 // and notify each one of this change.
1c79356b
A
1939 nextObject = priv->interestedDrivers->firstInList(); // notify interested drivers
1940 while ( nextObject != NULL ) {
1941 priv->head_note_pendingAcks +=1;
1942 if (! inform(nextObject, is_prechange) ) {
1943 }
1944 nextObject = priv->interestedDrivers->nextInList(nextObject);
1945 }
1946
1947 if (! acquire_lock() ) {
1948 return IOPMNoErr;
1949 }
1950 if ( priv->head_note_pendingAcks > 1 ) { // did they all ack?
1951 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0); // no
1952 start_ack_timer();
1953 }
1954 IOUnlock(priv->our_lock); // either way
1955
0b4e3aa0
A
1956 iter = getChildIterator(gIOPowerPlane); // notify children
1957 pm_vars->thePowerStates[priv->head_note_state].staticPower = 0; // summing their power consumption
1c79356b
A
1958
1959 if ( iter ) {
1960 while ( (next = iter->getNextObject()) ) {
1961 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
1962 priv->head_note_pendingAcks +=1;
1963 notifyChild(connection, is_prechange);
1964 }
1965 }
1966 iter->release();
1967 }
1968
1969 if (! acquire_lock() ) {
1970 return IOPMNoErr;
1971 }
1972 priv->head_note_pendingAcks -= 1; // now make this real
1973 if (priv->head_note_pendingAcks == 0 ) { // is it all acked?
1974 IOUnlock(priv->our_lock); // yes
1975 return IOPMAckImplied; // return ack to parent
1976 }
1977 IOUnlock(priv->our_lock); // no
1978 return IOPMWillAckLater;
1979}
1980
1981
1982//*********************************************************************************
1983// notifyChild
1984//
1985// Notify a power domain child of an upcoming power change.
1986//
1987// If the object acknowledges the current change, we return TRUE.
1988//*********************************************************************************
1989
1990bool IOService::notifyChild ( IOPowerConnection * theNub, bool is_prechange )
1991{
0b4e3aa0
A
1992 IOReturn k = IOPMAckImplied;
1993 unsigned long childPower;
1994 IOService * theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
1c79356b 1995
0b4e3aa0
A
1996 theNub->setAwaitingAck(true); // in case they don't ack
1997
1998 if ( ! theChild ) {
1999 return true;
2000 }
2001
1c79356b 2002 if ( is_prechange ) {
0b4e3aa0 2003 k = theChild->powerDomainWillChangeTo(priv->head_note_outputFlags,theNub);
1c79356b
A
2004 }
2005 else {
0b4e3aa0 2006 k = theChild->powerDomainDidChangeTo(priv->head_note_outputFlags,theNub);
1c79356b
A
2007 }
2008
0b4e3aa0
A
2009 if ( k == IOPMAckImplied ) { // did the return code ack?
2010 priv->head_note_pendingAcks -=1; // yes
2011 theNub->setAwaitingAck(false);
2012 childPower = theChild->currentPowerConsumption();
2013 if ( childPower == kIOPMUnknown ) {
2014 pm_vars->thePowerStates[priv->head_note_state].staticPower = kIOPMUnknown;
2015 }
2016 else {
2017 if ( pm_vars->thePowerStates[priv->head_note_state].staticPower != kIOPMUnknown ) {
2018 pm_vars->thePowerStates[priv->head_note_state].staticPower += childPower;
2019 }
2020 }
2021 theChild->release();
2022 return true;
1c79356b 2023 }
0b4e3aa0 2024 theChild->release();
1c79356b
A
2025 return false;
2026}
2027
2028
2029//*********************************************************************************
2030// inform
2031//
2032// Notify an interested driver of an upcoming power change.
2033//
2034// If the object acknowledges the current change, we return TRUE.
2035//*********************************************************************************
2036
2037bool IOService::inform ( IOPMinformee * nextObject, bool is_prechange )
2038{
2039 IOReturn k = IOPMAckImplied;
2040
2041 nextObject->timer = -1; // initialize this
2042
2043 if ( is_prechange ) {
2044 pm_vars->thePlatform->PMLog (pm_vars->ourName,PMlogInformDriverPreChange,
2045 (unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state);
2046 k = nextObject->whatObject->powerStateWillChangeTo( priv->head_note_capabilityFlags,priv->head_note_state,this);
2047 }
2048 else {
2049 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogInformDriverPostChange,
2050 (unsigned long)priv->head_note_capabilityFlags,(unsigned long)priv->head_note_state);
2051 k = nextObject->whatObject->powerStateDidChangeTo(priv->head_note_capabilityFlags,priv->head_note_state,this);
2052 }
1c79356b
A
2053 if ( nextObject->timer == 0 ) { // did it ack behind our back?
2054 return true; // yes
2055 }
2056 if ( k ==IOPMAckImplied ) { // no, did the return code ack?
2057 nextObject->timer = 0; // yes
2058 priv->head_note_pendingAcks -= 1;
2059 return true;
2060 }
2061 if ( k < 0 ) {
2062 nextObject->timer = 0; // somebody goofed
2063 priv-> head_note_pendingAcks -= 1;
2064 return true;
2065 }
2066 nextObject->timer = (k * ns_per_us / ACK_TIMER_PERIOD) + 1; // no, it's a timer
2067 return false;
2068}
2069
2070
2071//*********************************************************************************
2072// our_prechange_03
2073//
2074// All registered applications and kernel clients have positively acknowledged our
2075// intention of lowering power. Here we notify them all that we will definitely
2076// lower the power. If we don't have to wait for any of them to acknowledge, we
2077// carry on by notifying interested drivers. Otherwise, we do wait.
2078//*********************************************************************************
2079
2080void IOService::our_prechange_03 ( void )
0b4e3aa0
A
2081{
2082 priv->machine_state = IOPMour_prechange_04; // next state
2083 if ( tellChangeDown1(priv->head_note_state) ) { // are we waiting for responses?
2084 our_prechange_04(); // no, notify priority clients
2085 }
2086}
2087
2088
2089//*********************************************************************************
2090// our_prechange_04
2091//
2092// All registered applications and kernel clients have positively acknowledged our
2093// intention of lowering power. Here we notify "priority" clients that we are
2094// lowering power. If we don't have to wait for any of them to acknowledge, we
2095// carry on by notifying interested drivers. Otherwise, we do wait.
2096//*********************************************************************************
2097
2098void IOService::our_prechange_04 ( void )
1c79356b
A
2099{
2100 priv->machine_state = IOPMour_prechange_05; // next state
0b4e3aa0 2101 if ( tellChangeDown2(priv->head_note_state) ) { // are we waiting for responses?
1c79356b
A
2102 return our_prechange_05(); // no, notify interested drivers
2103 }
2104}
2105
2106
2107//*********************************************************************************
2108// our_prechange_05
2109//
2110// All registered applications and kernel clients have acknowledged our notification
2111// that we are lowering power. Here we notify interested drivers. If we don't have
2112// to wait for any of them to acknowledge, we instruct our power driver to make the change.
2113// Otherwise, we do wait.
2114//*********************************************************************************
2115
2116void IOService::our_prechange_05 ( void )
2117{
2118 priv->machine_state = IOPMour_prechange_1; // no, in case they don't all ack
2119 if ( notifyAll(true) == IOPMAckImplied ) {
2120 our_prechange_1();
2121 }
2122}
2123
2124
2125//*********************************************************************************
2126// our_prechange_1
2127//
2128// All interested drivers have acknowledged our pre-change notification of a power
2129// change we initiated. Here we instruct our controlling driver to make
2130// the change to the hardware. If it does so, we continue processing
2131// (waiting for settle and notifying interested parties post-change.)
2132// If it doesn't, we have to wait for it to acknowledge and then continue.
2133//*********************************************************************************
2134
2135void IOService::our_prechange_1 ( void )
2136{
2137 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
2138 our_prechange_2(); // it's done, carry on
2139 }
2140 else {
2141 priv->machine_state = IOPMour_prechange_2; // it's not, wait for it
2142 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
2143 start_ack_timer();
2144 }
2145}
2146
2147
2148//*********************************************************************************
2149// our_prechange_2
2150//
2151// Our controlling driver has changed power state on the hardware
2152// during a power change we initiated. Here we see if we need to wait
2153// for power to settle before continuing. If not, we continue processing
2154// (notifying interested parties post-change). If so, we wait and
2155// continue later.
2156//*********************************************************************************
2157
2158void IOService::our_prechange_2 ( void )
2159{
2160 priv->settle_time = compute_settle_time();
2161 if ( priv->settle_time == 0 ) {
2162 our_prechange_3();
2163 }
2164 else {
2165 priv->machine_state = IOPMour_prechange_3;
2166 startSettleTimer(priv->settle_time);
2167 }
2168}
2169
2170
2171//*********************************************************************************
2172// our_prechange_3
2173//
2174// Power has settled on a power change we initiated. Here we notify
2175// all our interested parties post-change. If they all acknowledge, we're
2176// done with this change note, and we can start on the next one.
2177// Otherwise we have to wait for acknowledgements and finish up later.
2178//*********************************************************************************
2179
2180void IOService::our_prechange_3 ( void )
2181{
2182 priv->machine_state = IOPMour_prechange_4; // in case they don't all ack
2183 if ( notifyAll(false) == IOPMAckImplied ) {
2184 our_prechange_4();
2185 }
2186}
2187
2188
2189//*********************************************************************************
2190// our_prechange_4
2191//
2192// Power has settled on a power change we initiated, and
2193// all our interested parties have acknowledged. We're
2194// done with this change note, and we can start on the next one.
2195//*********************************************************************************
2196
2197void IOService::our_prechange_4 ( void )
2198{
2199 all_done();
2200}
2201
2202
2203//*********************************************************************************
2204// parent_down_0
2205//
2206// All applications and kernel clients have been notified of a power lowering
2207// initiated by the parent and we didn't have to wait for any responses. Here
0b4e3aa0
A
2208// we notify any priority clients. If they all ack, we continue with the power change.
2209// If at least one doesn't, we have to wait for it to acknowledge and then continue.
2210//*********************************************************************************
2211
2212IOReturn IOService::parent_down_0 ( void )
2213{
2214 priv->machine_state = IOPMparent_down_05; // in case they don't all ack
2215 if ( tellChangeDown2(priv->head_note_state) ) { // are we waiting for responses?
2216 return parent_down_02(); // no, notify interested drivers
2217 }
2218 return IOPMWillAckLater; // they didn't
2219}
2220
2221
2222//*********************************************************************************
2223// parent_down_02
2224//
2225// All priority kernel clients have been notified of a power lowering
2226// initiated by the parent and we didn't have to wait for any responses. Here
1c79356b
A
2227// we notify any interested drivers and power domain children. If they all ack,
2228// we continue with the power change.
2229// If at least one doesn't, we have to wait for it to acknowledge and then continue.
2230//*********************************************************************************
2231
0b4e3aa0 2232IOReturn IOService::parent_down_02 ( void )
1c79356b
A
2233{
2234 priv->machine_state = IOPMparent_down_4; // in case they don't all ack
2235 if ( notifyAll(true) == IOPMAckImplied ) {
2236 return parent_down_1(); // they did
2237 }
2238 return IOPMWillAckLater; // they didn't
2239}
2240
2241
0b4e3aa0
A
2242//*********************************************************************************
2243// parent_down_04
2244//
2245// All applications and kernel clients have been notified of a power lowering
2246// initiated by the parent and we had to wait for responses. Here
2247// we notify any priority clients. If they all ack, we continue with the power change.
2248// If at least one doesn't, we have to wait for it to acknowledge and then continue.
2249//*********************************************************************************
2250
2251void IOService::parent_down_04 ( void )
2252{
2253 priv->machine_state = IOPMparent_down_05; // in case they don't all ack
2254 if ( tellChangeDown2(priv->head_note_state) ) { // are we waiting for responses?
2255 parent_down_05(); // no, notify interested drivers
2256 }
2257}
2258
2259
1c79356b
A
2260//*********************************************************************************
2261// parent_down_05
2262//
2263// All applications and kernel clients have been notified of a power lowering
2264// initiated by the parent and we had to wait for their responses. Here we notify
2265// any interested drivers and power domain children. If they all ack, we continue
2266// with the power change.
2267// If at least one doesn't, we have to wait for it to acknowledge and then continue.
2268//*********************************************************************************
2269
2270void IOService::parent_down_05 ( void )
2271{
2272 priv->machine_state = IOPMparent_down_4; // in case they don't all ack
2273 if ( notifyAll(true) == IOPMAckImplied ) {
2274 parent_down_4(); // they did
2275 }
2276}
2277
2278
2279//*********************************************************************************
2280// parent_down_1
2281//
2282// All parties have acknowledged our pre-change notification of a power
2283// lowering initiated by the parent. Here we instruct our controlling driver
2284// to put the hardware in the state it needs to be in when the domain is
2285// lowered. If it does so, we continue processing
2286// (waiting for settle and acknowledging the parent.)
2287// If it doesn't, we have to wait for it to acknowledge and then continue.
2288//*********************************************************************************
2289
2290IOReturn IOService::parent_down_1 ( void )
2291{
2292 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
2293 return parent_down_2(); // it's done, carry on
2294 }
2295 priv->machine_state = IOPMparent_down_5; // it's not, wait for it
2296 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
2297 start_ack_timer();
2298 return IOPMWillAckLater;
2299}
2300
2301
2302//*********************************************************************************
2303// parent_down_4
2304//
2305// We had to wait for it, but all parties have acknowledged our pre-change
2306// notification of a power lowering initiated by the parent.
2307// Here we instruct our controlling driver
2308// to put the hardware in the state it needs to be in when the domain is
2309// lowered. If it does so, we continue processing
2310// (waiting for settle and acknowledging the parent.)
2311// If it doesn't, we have to wait for it to acknowledge and then continue.
2312//*********************************************************************************
2313
2314void IOService::parent_down_4 ( void )
2315{
2316 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
2317 parent_down_5(); // it's done, carry on
2318 }
2319 else {
2320 priv-> machine_state = IOPMparent_down_5; // it's not, wait for it
2321 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
2322 start_ack_timer();
2323 }
2324}
2325
2326
2327//*********************************************************************************
2328// parent_down_2
2329//
2330// Our controlling driver has changed power state on the hardware
2331// during a power change initiated by our parent. Here we see if we need
2332// to wait for power to settle before continuing. If not, we continue
2333// processing (acknowledging our preparedness to the parent).
2334// If so, we wait and continue later.
2335//*********************************************************************************
2336
2337IOReturn IOService::parent_down_2 ( void )
2338{
0b4e3aa0
A
2339 IOService * nub;
2340
1c79356b
A
2341 priv->settle_time = compute_settle_time();
2342 if ( priv->settle_time == 0 ) {
2343 priv->machine_state = IOPMparent_down_6; // in case they don't all ack
2344 if ( notifyAll(false) == IOPMAckImplied ) {
0b4e3aa0 2345 nub = priv->head_note_parent;
1c79356b 2346 all_done();
0b4e3aa0 2347 nub->release();
1c79356b
A
2348 return IOPMAckImplied;
2349 }
2350 return IOPMWillAckLater; // they didn't
2351 }
2352 else {
2353 priv->machine_state = IOPMparent_down_3;
2354 startSettleTimer(priv->settle_time);
2355 return IOPMWillAckLater;
2356 }
2357}
2358
2359
2360//*********************************************************************************
2361// parent_down_5
2362//
2363// Our controlling driver has changed power state on the hardware
2364// during a power change initiated by our parent. We have had to wait
2365// for acknowledgement from interested parties, or we have had to wait
2366// for the controlling driver to change the state. Here we see if we need
2367// to wait for power to settle before continuing. If not, we continue
2368// processing (acknowledging our preparedness to the parent).
2369// If so, we wait and continue later.
2370//*********************************************************************************
2371
2372void IOService::parent_down_5 ( void )
2373{
2374 priv->settle_time = compute_settle_time();
2375 if ( priv->settle_time == 0 ) {
2376 parent_down_3();
2377 }
2378 else {
2379 priv->machine_state = IOPMparent_down_3;
2380 startSettleTimer(priv->settle_time);
2381 }
2382}
2383
2384
2385//*********************************************************************************
2386// parent_down_3
2387//
2388// Power has settled on a power change initiated by our parent. Here we
2389// notify interested parties.
2390//*********************************************************************************
2391
2392void IOService::parent_down_3 ( void )
2393{
0b4e3aa0
A
2394 IORegistryEntry * nub;
2395 IOService * parent;
1c79356b
A
2396
2397 priv->machine_state = IOPMparent_down_6; // in case they don't all ack
2398 if ( notifyAll(false) == IOPMAckImplied ) {
0b4e3aa0 2399 nub = priv->head_note_parent;
1c79356b 2400 all_done();
0b4e3aa0
A
2401 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
2402 if ( parent ) {
2403 parent->acknowledgePowerChange((IOService *)nub);
2404 parent->release();
2405 }
2406 nub->release();
1c79356b
A
2407 }
2408}
2409
2410
2411//*********************************************************************************
2412// parent_down_6
2413//
2414// We had to wait for it, but all parties have acknowledged our post-change
2415// notification of a power lowering initiated by the parent.
2416// Here we acknowledge the parent.
2417// We are done with this change note, and we can start on the next one.
2418//*********************************************************************************
2419
2420void IOService::parent_down_6 ( void )
2421{
0b4e3aa0
A
2422 IORegistryEntry * nub;
2423 IOService * parent;
1c79356b 2424
0b4e3aa0 2425 nub = priv->head_note_parent;
1c79356b 2426 all_done();
0b4e3aa0
A
2427 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
2428 if ( parent ) {
2429 parent->acknowledgePowerChange((IOService *)nub);
2430 parent->release();
2431 }
2432 nub->release();
1c79356b
A
2433}
2434
2435
2436//*********************************************************************************
2437// parent_up_0
2438//
2439// Our parent has informed us via powerStateDidChange that it has
2440// raised the power in our power domain, and we have had to wait
2441// for some interested party to acknowledge our notification.
2442// Here we instruct our controlling
2443// driver to program the hardware to take advantage of the higher domain
2444// power. If it does so, we continue processing
2445// (waiting for settle and notifying interested parties post-change.)
2446// If it doesn't, we have to wait for it to acknowledge and then continue.
2447//*********************************************************************************
2448
2449void IOService::parent_up_0 ( void )
2450{
2451 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
2452 parent_up_4(); // it did it, carry on
2453 }
2454 else {
2455 priv->machine_state = IOPMparent_up_4; // it didn't, wait for it
2456 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
2457 start_ack_timer();
2458 }
2459}
2460
2461
2462//*********************************************************************************
2463// parent_up_1
2464//
2465// Our parent has informed us via powerStateDidChange that it has
2466// raised the power in our power domain. Here we instruct our controlling
2467// driver to program the hardware to take advantage of the higher domain
2468// power. If it does so, we continue processing
2469// (waiting for settle and notifying interested parties post-change.)
2470// If it doesn't, we have to wait for it to acknowledge and then continue.
2471//*********************************************************************************
2472
2473IOReturn IOService::parent_up_1 ( void )
2474{
2475 if ( instruct_driver(priv->head_note_state) == IOPMAckImplied ) {
2476 return parent_up_2(); // it did it, carry on
2477 }
2478 else {
2479 priv->machine_state = IOPMparent_up_4; // it didn't, wait for it
2480 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,0,0);
2481 start_ack_timer();
2482 return IOPMWillAckLater;
2483 }
2484}
2485
2486
2487//*********************************************************************************
2488// parent_up_2
2489//
2490// Our controlling driver has changed power state on the hardware
2491// during a power raise initiated by the parent. Here we see if we need to wait
2492// for power to settle before continuing. If not, we continue processing
2493// (notifying interested parties post-change). If so, we wait and
2494// continue later.
2495//*********************************************************************************
2496
2497IOReturn IOService::parent_up_2 ( void )
2498{
2499 priv->settle_time = compute_settle_time();
2500 if ( priv->settle_time == 0 ) {
2501 return parent_up_3();
2502 }
2503 else {
2504 priv->machine_state = IOPMparent_up_5;
2505 startSettleTimer(priv->settle_time);
2506 return IOPMWillAckLater;
2507 }
2508}
2509
2510
2511//*********************************************************************************
2512// parent_up_4
2513//
2514// Our controlling driver has changed power state on the hardware
2515// during a power raise initiated by the parent, but we had to wait for it.
2516// Here we see if we need to wait for power to settle before continuing.
2517// If not, we continue processing (notifying interested parties post-change).
2518// If so, we wait and continue later.
2519//*********************************************************************************
2520
2521void IOService::parent_up_4 ( void )
2522{
2523 priv->settle_time = compute_settle_time();
2524 if ( priv->settle_time == 0 ) {
2525 parent_up_5();
2526 }
2527 else {
2528 priv->machine_state = IOPMparent_up_5;
2529 startSettleTimer(priv->settle_time);
2530 }
2531}
2532
2533
2534//*********************************************************************************
2535// parent_up_3
2536//
2537// No power settling was required on a power raise initiated by the parent.
2538// Here we notify all our interested parties post-change. If they all acknowledge,
2539// we're done with this change note, and we can start on the next one.
2540// Otherwise we have to wait for acknowledgements and finish up later.
2541//*********************************************************************************
2542
2543IOReturn IOService::parent_up_3 ( void )
2544{
0b4e3aa0
A
2545 IOService * nub;
2546
1c79356b
A
2547 priv->machine_state = IOPMparent_up_6; // in case they don't all ack
2548 if ( notifyAll(false) == IOPMAckImplied ) {
0b4e3aa0 2549 nub = priv->head_note_parent;
1c79356b 2550 all_done();
0b4e3aa0 2551 nub->release();
1c79356b
A
2552 return IOPMAckImplied;
2553 }
2554 return IOPMWillAckLater; // they didn't
2555}
2556
2557
2558//*********************************************************************************
2559// parent_up_5
2560//
2561// Power has settled on a power raise initiated by the parent.
2562// Here we notify all our interested parties post-change. If they all acknowledge,
2563// we're done with this change note, and we can start on the next one.
2564// Otherwise we have to wait for acknowledgements and finish up later.
2565//*********************************************************************************
2566
2567void IOService::parent_up_5 ( void )
2568{
2569 priv->machine_state = IOPMparent_up_6; // in case they don't all ack
2570 if ( notifyAll(false) == IOPMAckImplied ) {
2571 parent_up_6();
2572 }
2573}
2574
2575
2576//*********************************************************************************
2577// parent_up_6
2578//
2579// All parties have acknowledged our post-change notification of a power
2580// raising initiated by the parent. Here we acknowledge the parent.
2581// We are done with this change note, and we can start on the next one.
2582//*********************************************************************************
2583
2584void IOService::parent_up_6 ( void )
2585{
0b4e3aa0
A
2586 IORegistryEntry * nub;
2587 IOService * parent;
1c79356b 2588
0b4e3aa0 2589 nub = priv->head_note_parent;
1c79356b 2590 all_done();
0b4e3aa0
A
2591 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
2592 if ( parent ) {
2593 parent->acknowledgePowerChange((IOService *)nub);
2594 parent->release();
2595 }
2596 nub->release();
1c79356b
A
2597}
2598
2599
2600//*********************************************************************************
2601// all_done
2602//
2603// A power change is complete, and the used post-change note is at
2604// the head of the queue. Remove it and set myCurrentState to the result
2605// of the change. Start up the next change in queue.
2606//*********************************************************************************
2607
2608void IOService::all_done ( void )
0b4e3aa0
A
2609{
2610 unsigned long previous_state;
2611 IORegistryEntry * nub;
2612 IOService * parent;
2613
1c79356b
A
2614 priv->machine_state = IOPMfinished;
2615
2616 if ( priv->head_note_flags & IOPMWeInitiated ) { // our power change
2617 if ( !( priv->head_note_flags & IOPMNotDone) ) { // could our driver switch to the new state?
2618 if ( pm_vars->myCurrentState < priv->head_note_state ) { // yes, did power raise?
2619 tellChangeUp (priv->head_note_state); // yes, inform clients and apps
2620 }
2621 else {
2622 if ( ! priv->we_are_root ) { // no, if this lowers our
2623 ask_parent(priv->head_note_state); // power requirements, tell the parent
2624 }
2625 }
0b4e3aa0 2626 previous_state = pm_vars->myCurrentState;
1c79356b 2627 pm_vars->myCurrentState = priv->head_note_state; // either way
0b4e3aa0 2628 priv->imminentState = pm_vars->myCurrentState;
1c79356b 2629 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0);
0b4e3aa0 2630 powerChangeDone(previous_state); // inform subclass policy-maker
1c79356b
A
2631 }
2632// else { // no
2633// pm_vars->myCurrentState = pm_vars->theControllingDriver->powerStateForDomainState(pm_vars->parentsCurrentPowerFlags);
2634// }
2635 }
2636 if ( priv->head_note_flags & IOPMParentInitiated) { // parent's power change
2637 if ( ((priv->head_note_flags & IOPMDomainWillChange) && (pm_vars->myCurrentState >= priv->head_note_state)) ||
2638 ((priv->head_note_flags & IOPMDomainDidChange) && (pm_vars->myCurrentState < priv->head_note_state)) ) {
2639 if ( pm_vars->myCurrentState < priv->head_note_state ) { // did power raise?
2640 tellChangeUp (priv->head_note_state); // yes, inform clients and apps
2641 }
0b4e3aa0
A
2642 previous_state = pm_vars->myCurrentState; // either way
2643 pm_vars->myCurrentState = priv->head_note_state;
2644 priv->imminentState = pm_vars->myCurrentState;
1c79356b
A
2645 pm_vars->maxCapability = pm_vars->theControllingDriver->maxCapabilityForDomainState(priv->head_note_domainState);
2646
2647 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogChangeDone,(unsigned long)pm_vars->myCurrentState,0);
0b4e3aa0 2648 powerChangeDone(previous_state); // inform subclass policy-maker
1c79356b
A
2649 }
2650 }
2651
0b4e3aa0 2652 IOLockLock(priv->queue_lock);
1c79356b
A
2653 priv->changeList->releaseHeadChangeNote(); // we're done with this
2654
0b4e3aa0 2655 priv->head_note = priv->changeList->currentChange(); // start next one in queue
1c79356b
A
2656 if ( priv->head_note != -1 ) {
2657
0b4e3aa0 2658 IOLockUnlock(priv->queue_lock);
1c79356b
A
2659 if (priv->changeList->changeNote[priv->head_note].flags & IOPMWeInitiated ) {
2660 start_our_change(priv->head_note);
2661 }
2662 else {
0b4e3aa0 2663 nub = priv->changeList->changeNote[priv->head_note].parent;
1c79356b 2664 if ( start_parent_change(priv->head_note) == IOPMAckImplied ) {
0b4e3aa0
A
2665 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
2666 if ( parent ) {
2667 parent->acknowledgePowerChange((IOService *)nub);
2668 parent->release();
2669 }
1c79356b
A
2670 }
2671 }
2672 }
0b4e3aa0 2673 IOLockUnlock(priv->queue_lock);
1c79356b
A
2674}
2675
2676
2677
2678//*********************************************************************************
2679// all_acked
2680//
2681// A driver or child has acknowledged our notification of an upcoming power
2682// change, and this acknowledgement is the last one pending
2683// before we change power or after changing power.
2684//
2685//*********************************************************************************
2686
2687void IOService::all_acked ( void )
2688{
2689 switch (priv->machine_state) {
2690 case IOPMour_prechange_1:
2691 our_prechange_1();
2692 break;
2693 case IOPMour_prechange_4:
2694 our_prechange_4();
2695 break;
2696 case IOPMparent_down_4:
2697 parent_down_4();
2698 break;
2699 case IOPMparent_down_6:
2700 parent_down_6();
2701 break;
2702 case IOPMparent_up_0:
2703 parent_up_0();
2704 break;
2705 case IOPMparent_up_6:
2706 parent_up_6();
2707 break;
2708 }
2709}
2710
2711
2712//*********************************************************************************
2713// settleTimerExpired
2714//
2715// Power has settled after our last change. Notify interested parties that
2716// there is a new power state.
2717//*********************************************************************************
2718
2719void IOService::settleTimerExpired ( void )
2720{
2721 if ( ! initialized ) {
2722 return; // we're unloading
2723 }
2724
2725 switch (priv->machine_state) {
2726 case IOPMour_prechange_3:
2727 our_prechange_3();
2728 break;
2729 case IOPMparent_down_3:
2730 parent_down_3();
2731 break;
2732 case IOPMparent_up_5:
2733 parent_up_5();
2734 break;
2735 }
2736}
2737
2738
2739//*********************************************************************************
2740// compute_settle_time
2741//
2742// Compute the power-settling delay in microseconds for the
2743// change from myCurrentState to head_note_state.
2744//*********************************************************************************
2745
2746unsigned long IOService::compute_settle_time ( void )
2747{
2748 unsigned long totalTime;
2749 unsigned long i;
2750
2751 totalTime = 0; // compute total time to attain the new state
2752 i = pm_vars->myCurrentState;
2753 if ( priv->head_note_state < pm_vars->myCurrentState ) { // we're lowering power
2754 while ( i > priv->head_note_state ) {
2755 totalTime += pm_vars->thePowerStates[i].settleDownTime;
2756 i--;
2757 }
2758 }
2759
2760 if ( priv->head_note_state > pm_vars->myCurrentState ) { // we're raising power
2761 while ( i < priv->head_note_state ) {
2762 totalTime += pm_vars->thePowerStates[i+1].settleUpTime;
2763 i++;
2764 }
2765 }
2766
2767 return totalTime;
2768}
2769
2770
2771//*********************************************************************************
2772// startSettleTimer
2773//
2774// Enter with a power-settling delay in microseconds and start a nano-second
2775// timer for that delay.
2776//*********************************************************************************
2777
2778IOReturn IOService::startSettleTimer ( unsigned long delay )
2779{
2780 AbsoluteTime deadline;
2781
2782 clock_interval_to_deadline(delay, kMicrosecondScale, &deadline);
2783
2784 thread_call_enter_delayed(priv->settleTimer, deadline);
2785
2786 return IOPMNoErr;
2787}
2788
2789//*********************************************************************************
2790// ack_timer_ticked
2791//
2792// The acknowledgement timeout periodic timer has ticked.
2793// If we are awaiting acks for a power change notification,
2794// we decrement the timer word of each interested driver which hasn't acked.
2795// If a timer word becomes zero, we pretend the driver aknowledged.
2796// If we are waiting for the controlling driver to change the power
2797// state of the hardware, we decrement its timer word, and if it becomes
2798// zero, we pretend the driver acknowledged.
2799//*********************************************************************************
2800
2801void IOService::ack_timer_ticked ( void )
2802{
2803 IOPMinformee * nextObject;
2804
2805 if ( ! initialized ) {
2806 return; // we're unloading
2807 }
2808
2809 if (! acquire_lock() ) {
2810 return;
2811 }
2812
2813 switch (priv->machine_state) {
2814 case IOPMour_prechange_2:
2815 case IOPMparent_down_5:
2816 case IOPMparent_up_4:
2817 if ( priv->driver_timer != 0 ) { // are we waiting for our driver to make its change?
2818 priv->driver_timer -= 1; // yes, tick once
2819 if ( priv->driver_timer == 0 ) { // it's tardy, we'll go on without it
2820 IOUnlock(priv->our_lock);
2821 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogCtrlDriverTardy,0,0);
2822 driver_acked();
2823 }
2824 else { // still waiting, set timer again
2825 start_ack_timer();
2826 IOUnlock(priv->our_lock);
2827 }
2828 }
2829 else {
2830 IOUnlock(priv->our_lock);
2831 }
2832 break;
2833
2834 case IOPMour_prechange_1:
2835 case IOPMour_prechange_4:
2836 case IOPMparent_down_4:
2837 case IOPMparent_down_6:
2838 case IOPMparent_up_0:
2839 case IOPMparent_up_6:
2840 if (priv->head_note_pendingAcks != 0 ) { // are we waiting for interested parties to acknowledge?
2841 nextObject = priv->interestedDrivers->firstInList(); // yes, go through the list of interested drivers
2842 while ( nextObject != NULL ) { // and check each one
2843 if ( nextObject->timer > 0 ) {
2844 nextObject->timer -= 1;
2845 if ( nextObject->timer == 0 ) { // this one should have acked by now
2846 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogIntDriverTardy,0,0);
2847 kprintf("interested driver tardy: %s\n",nextObject->whatObject->getName());
2848 priv->head_note_pendingAcks -= 1;
2849 }
2850 }
2851 nextObject = priv->interestedDrivers->nextInList(nextObject);
2852 }
2853 if ( priv->head_note_pendingAcks == 0 ) { // is that the last?
2854 IOUnlock(priv->our_lock);
2855 all_acked(); // yes, we can continue
2856 }
2857 else { // no, set timer again
2858 start_ack_timer();
2859 IOUnlock(priv->our_lock);
2860 }
2861 }
2862 else {
2863 IOUnlock(priv->our_lock);
2864 }
2865 break;
2866
2867 case IOPMparent_down_0: // apps didn't respond to parent-down notification
0b4e3aa0
A
2868 IOUnlock(priv->our_lock);
2869 IOLockLock(priv->flags_lock);
2870 if (pm_vars->responseFlags) {
2871 pm_vars->responseFlags->release(); // get rid of this stuff
2872 pm_vars->responseFlags = NULL;
2873 }
2874 IOLockUnlock(priv->flags_lock);
2875 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,5);
2876 parent_down_04(); // carry on with the change
2877 break;
2878
2879 case IOPMparent_down_05:
1c79356b
A
2880 IOUnlock(priv->our_lock);
2881 IOLockLock(priv->flags_lock);
2882 if (pm_vars->responseFlags) {
2883 pm_vars->responseFlags->release(); // get rid of this stuff
2884 pm_vars->responseFlags = NULL;
2885 }
2886 IOLockUnlock(priv->flags_lock);
2887 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,1);
2888 parent_down_05(); // carry on with the change
2889 break;
2890
2891 case IOPMour_prechange_03: // apps didn't respond to our power-down request
2892 IOUnlock(priv->our_lock);
2893 IOLockLock(priv->flags_lock);
2894 if (pm_vars->responseFlags) {
2895 pm_vars->responseFlags->release(); // get rid of this stuff
2896 pm_vars->responseFlags = NULL;
2897 }
2898 IOLockUnlock(priv->flags_lock);
2899 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,2);
2900 tellNoChangeDown(priv->head_note_state); // rescind the request
2901 priv->head_note_flags |= IOPMNotDone; // mark the change note un-actioned
2902 all_done(); // and we're done
2903 break;
2904
0b4e3aa0
A
2905 case IOPMour_prechange_04: // clients didn't respond to our power-down note
2906 IOUnlock(priv->our_lock);
2907 IOLockLock(priv->flags_lock);
2908 if (pm_vars->responseFlags) {
2909 pm_vars->responseFlags->release(); // get rid of this stuff
2910 pm_vars->responseFlags = NULL;
2911 }
2912 IOLockUnlock(priv->flags_lock);
2913 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,4);
2914 our_prechange_04(); // carry on with the change
2915 break;
2916
1c79356b
A
2917 case IOPMour_prechange_05: // apps didn't respond to our power-down notification
2918 IOUnlock(priv->our_lock);
2919 IOLockLock(priv->flags_lock);
2920 if (pm_vars->responseFlags) {
2921 pm_vars->responseFlags->release(); // get rid of this stuff
2922 pm_vars->responseFlags = NULL;
2923 }
2924 IOLockUnlock(priv->flags_lock);
2925 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientTardy,0,3);
2926 our_prechange_05(); // carry on with the change
2927 break;
2928
2929 default:
2930 IOUnlock(priv->our_lock); // not waiting for acks
2931 break;
2932 }
2933}
2934
2935
2936//*********************************************************************************
2937// start_ack_timer
2938//
2939//*********************************************************************************
2940
2941void IOService::start_ack_timer ( void )
2942{
2943 AbsoluteTime deadline;
2944
2945 clock_interval_to_deadline(ACK_TIMER_PERIOD, kNanosecondScale, &deadline);
2946
2947 thread_call_enter_delayed(priv->ackTimer, deadline);
2948}
2949
2950
2951//*********************************************************************************
2952// stop_ack_timer
2953//
2954//*********************************************************************************
2955
2956void IOService::stop_ack_timer ( void )
2957{
2958 thread_call_cancel(priv->ackTimer);
2959}
2960
2961
2962//*********************************************************************************
2963// c-language timer expiration functions
2964//
2965//*********************************************************************************
2966
2967static void ack_timer_expired ( thread_call_param_t us)
2968{
2969 ((IOService *)us)->ack_timer_ticked();
2970}
2971
2972
2973static void settle_timer_expired ( thread_call_param_t us)
2974{
2975 ((IOService *)us)->settleTimerExpired();
2976}
2977
2978
2979//*********************************************************************************
2980// add_child_to_active_change
2981//
2982// A child has just registered with us. If there is
2983// currently a change in progress, get the new party involved: if we
2984// have notified all parties and are waiting for acks, notify the new
2985// party.
2986//*********************************************************************************
2987
2988IOReturn IOService::add_child_to_active_change ( IOPowerConnection * newObject )
2989{
2990 if (! acquire_lock() ) {
2991 return IOPMNoErr;
2992 }
2993
2994 switch (priv->machine_state) {
2995 case IOPMour_prechange_1:
2996 case IOPMparent_down_4:
2997 case IOPMparent_up_0:
2998 priv->head_note_pendingAcks += 2; // one for this child and one to prevent
2999 IOUnlock(priv->our_lock); // incoming acks from changing our state
3000 notifyChild(newObject, true);
3001 if (! acquire_lock() ) {
3002 --priv->head_note_pendingAcks; // put it back
3003 return IOPMNoErr;
3004 }
3005 if ( --priv->head_note_pendingAcks == 0 ) { // are we still waiting for acks?
3006 stop_ack_timer(); // no, stop the timer
3007 IOUnlock(priv->our_lock);
3008 all_acked(); // and now we can continue
3009 return IOPMNoErr;
3010 }
3011 break;
3012 case IOPMour_prechange_4:
3013 case IOPMparent_down_6:
3014 case IOPMparent_up_6:
3015 priv->head_note_pendingAcks += 2; // one for this child and one to prevent
3016 IOUnlock(priv->our_lock); // incoming acks from changing our state
3017 notifyChild(newObject, false);
3018 if (! acquire_lock() ) {
3019 --priv->head_note_pendingAcks; // put it back
3020 return IOPMNoErr;
3021 }
3022 if ( --priv->head_note_pendingAcks == 0 ) { // are we still waiting for acks?
3023 stop_ack_timer(); // no, stop the timer
3024 IOUnlock(priv->our_lock);
3025 all_acked(); // and now we can continue
3026 return IOPMNoErr;
3027 }
3028 break;
3029 }
3030 IOUnlock(priv->our_lock);
3031 return IOPMNoErr;
3032}
3033
3034
3035//*********************************************************************************
3036// add_driver_to_active_change
3037//
3038// An interested driver has just registered with us. If there is
3039// currently a change in progress, get the new party involved: if we
3040// have notified all parties and are waiting for acks, notify the new
3041// party.
3042//*********************************************************************************
3043
3044IOReturn IOService::add_driver_to_active_change ( IOPMinformee * newObject )
3045{
3046 if (! acquire_lock() ) {
3047 return IOPMNoErr;
3048 }
3049
3050 switch (priv->machine_state) {
3051 case IOPMour_prechange_1:
3052 case IOPMparent_down_4:
3053 case IOPMparent_up_0:
3054 priv->head_note_pendingAcks += 2; // one for this driver and one to prevent
3055 IOUnlock(priv->our_lock); // incoming acks from changing our state
3056 inform(newObject, true); // inform the driver
3057 if (! acquire_lock() ) {
3058 --priv->head_note_pendingAcks; // put it back
3059 return IOPMNoErr;
3060 }
3061 if ( --priv->head_note_pendingAcks == 0 ) { // are we still waiting for acks?
3062 stop_ack_timer(); // no, stop the timer
3063 IOUnlock(priv->our_lock);
3064 all_acked(); // and now we can continue
3065 return IOPMNoErr;
3066 }
3067 break;
3068 case IOPMour_prechange_4:
3069 case IOPMparent_down_6:
3070 case IOPMparent_up_6:
3071 priv->head_note_pendingAcks += 2; // one for this driver and one to prevent
3072 IOUnlock(priv->our_lock); // incoming acks from changing our state
3073 inform(newObject, false); // inform the driver
3074 if (! acquire_lock() ) {
3075 --priv->head_note_pendingAcks; // put it back
3076 return IOPMNoErr;
3077 }
3078 if ( --priv->head_note_pendingAcks == 0 ) { // are we still waiting for acks?
3079 stop_ack_timer(); // no, stop the timer
3080 IOUnlock(priv->our_lock);
3081 all_acked(); // and now we can continue
3082 return IOPMNoErr;
3083 }
3084 break;
3085 }
3086 IOUnlock(priv->our_lock);
3087 return IOPMNoErr;
3088}
3089
3090
3091//*********************************************************************************
3092// start_parent_change
3093//
3094// Here we begin the processing of a change note initiated by our parent
3095// which is at the head of the queue.
3096//
3097// It is possible for the change to be processed to completion and removed from the queue.
3098// There are several possible interruptions to the processing, though, and they are:
3099// we may have to wait for interested parties to acknowledge our pre-change notification,
3100// we may have to wait for our controlling driver to change the hardware power state,
3101// there may be a settling time after changing the hardware power state,
3102// we may have to wait for interested parties to acknowledge our post-change notification,
3103// we may have to wait for the acknowledgement timer expiration to substitute for the
3104// acknowledgement from a failing driver.
3105//*********************************************************************************
3106
3107IOReturn IOService::start_parent_change ( unsigned long queue_head )
3108{
3109 priv->head_note = queue_head;
3110 priv->head_note_flags = priv-> changeList->changeNote[priv->head_note].flags;
3111 priv->head_note_state = priv->changeList->changeNote[priv->head_note].newStateNumber;
0b4e3aa0 3112 priv->imminentState = priv->head_note_state;
1c79356b
A
3113 priv->head_note_outputFlags = priv->changeList->changeNote[priv->head_note].outputPowerCharacter;
3114 priv->head_note_domainState = priv->changeList->changeNote[priv->head_note].domainState;
3115 priv->head_note_parent = priv->changeList->changeNote[priv->head_note].parent;
3116 priv->head_note_capabilityFlags = priv->changeList->changeNote[priv->head_note].capabilityFlags;
3117
3118 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartParentChange,
3119 (unsigned long)priv->head_note_state,(unsigned long)pm_vars->myCurrentState);
3120
3121 ask_parent( priv->ourDesiredPowerState); // if we need something and haven't told the parent, do so
3122
3123 if ( priv->head_note_state < pm_vars->myCurrentState ) { // power domain is lowering
0b4e3aa0 3124 setParentInfo(priv->changeList->changeNote[priv->head_note].singleParentState,priv->head_note_parent);
1c79356b
A
3125 priv->initial_change = false;
3126 priv->machine_state = IOPMparent_down_0; // tell apps and kernel clients
0b4e3aa0
A
3127 if ( tellChangeDown1(priv->head_note_state) ) { // are we waiting for responses?
3128 return parent_down_0(); // no, notify priority clients
1c79356b
A
3129 }
3130 return IOPMWillAckLater; // yes
3131 }
3132
3133 if ( priv->head_note_state > pm_vars->myCurrentState ) { // parent is raising power, we may or may not
3134 if ( priv->ourDesiredPowerState > pm_vars->myCurrentState ) {
3135 if ( priv->ourDesiredPowerState < priv->head_note_state ) {
3136 priv->head_note_state = priv->ourDesiredPowerState; // we do, but not all the way
0b4e3aa0 3137 priv->imminentState = priv->head_note_state;
1c79356b
A
3138 priv->head_note_outputFlags = pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter;
3139 priv->head_note_capabilityFlags = pm_vars->thePowerStates[priv->head_note_state].capabilityFlags;
3140 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0);
3141 }
3142 }
3143 else {
0b4e3aa0
A
3144 priv->head_note_state = pm_vars->myCurrentState; // we don't
3145 priv->imminentState = priv->head_note_state;
1c79356b
A
3146 priv->head_note_outputFlags = pm_vars->thePowerStates[priv->head_note_state].outputPowerCharacter;
3147 priv->head_note_capabilityFlags = pm_vars->thePowerStates[priv->head_note_state].capabilityFlags;
3148 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAmendParentChange,(unsigned long)priv->head_note_state,0);
3149 }
3150 }
3151
3152 if ( (priv->head_note_state > pm_vars->myCurrentState) &&
3153 (priv->head_note_flags & IOPMDomainDidChange) ) { // changing up
3154 priv->initial_change = false;
3155 priv->machine_state = IOPMparent_up_0;
3156 if ( notifyAll(true) == IOPMAckImplied ) {
3157 return parent_up_1();
3158 }
3159 return IOPMWillAckLater; // they didn't all ack
3160 }
3161
3162 all_done();
3163 return IOPMAckImplied; // a null change or power will go up
3164}
3165
3166
3167//*********************************************************************************
3168// start_our_change
3169//
3170// Here we begin the processing of a change note initiated by us
3171// which is at the head of the queue.
3172//
3173// It is possible for the change to be processed to completion and removed from the queue.
3174// There are several possible interruptions to the processing, though, and they are:
3175// we may have to wait for interested parties to acknowledge our pre-change notification,
3176// changes initiated by the parent will wait in the middle for powerStateDidChange,
3177// we may have to wait for our controlling driver to change the hardware power state,
3178// there may be a settling time after changing the hardware power state,
3179// we may have to wait for interested parties to acknowledge our post-change notification,
3180// we may have to wait for the acknowledgement timer expiration to substitute for the
3181// acknowledgement from a failing driver.
3182//*********************************************************************************
3183
3184void IOService::start_our_change ( unsigned long queue_head )
3185{
3186 priv->head_note = queue_head;
3187 priv->head_note_flags = priv->changeList->changeNote[priv->head_note].flags;
3188 priv->head_note_state = priv->changeList->changeNote[priv->head_note].newStateNumber;
0b4e3aa0 3189 priv->imminentState = priv->head_note_state;
1c79356b
A
3190 priv->head_note_outputFlags = priv->changeList->changeNote[priv->head_note].outputPowerCharacter;
3191 priv->head_note_capabilityFlags = priv->changeList->changeNote[priv->head_note].capabilityFlags;
3192
3193 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartDeviceChange,
3194 (unsigned long)priv->head_note_state,(unsigned long)pm_vars->myCurrentState);
3195
3196 if ( priv->head_note_capabilityFlags & IOPMNotAttainable ) { // can our driver switch to the new state?
3197 if ( ! priv->we_are_root ) { // no, ask the parent to do it then
3198 ask_parent(priv->head_note_state);
3199 }
3200 priv-> head_note_flags |= IOPMNotDone; // mark the change note un-actioned
3201 all_done(); // and we're done
3202 return;
3203 }
3204 // is there enough power in the domain?
3205 if ( (pm_vars->maxCapability < priv->head_note_state) && (! priv->we_are_root) ) {
3206 if ( ! priv->we_are_root ) { // no, ask the parent to raise it
3207 ask_parent(priv->head_note_state);
3208 }
3209 priv->head_note_flags |= IOPMNotDone; // no, mark the change note un-actioned
3210 all_done(); // and we're done
3211 return; // till the parent raises power
3212 }
3213
3214 if ( ! priv->initial_change ) {
3215 if ( priv->head_note_state == pm_vars->myCurrentState ) {
3216 all_done(); // we initiated a null change; forget it
3217 return;
3218 }
3219 }
3220 priv->initial_change = false;
3221
3222 if ( priv->head_note_state < pm_vars->myCurrentState ) { // dropping power?
3223 priv->machine_state = IOPMour_prechange_03; // yes, in case we have to wait for acks
3224 pm_vars->doNotPowerDown = false;
7b1edb79
A
3225 pm_vars->outofbandparameter = kNotifyApps; // ask apps and kernel clients if we can drop power
3226 if ( askChangeDown(priv->head_note_state) ) {
1c79356b
A
3227 if ( pm_vars->doNotPowerDown ) { // don't have to wait, did any clients veto?
3228 tellNoChangeDown(priv->head_note_state); // yes, rescind the warning
3229 priv-> head_note_flags |= IOPMNotDone; // mark the change note un-actioned
3230 all_done(); // and we're done
3231 }
3232 else {
3233 our_prechange_03(); // no, tell'em we're dropping power
3234 }
3235 }
3236 }
3237 else {
3238 if ( ! priv->we_are_root ) { // we are raising power
3239 ask_parent(priv->head_note_state); // if this changes our power requirement, tell the parent
3240 }
3241 priv->machine_state = IOPMour_prechange_1; // in case they don't all ack
3242 if ( notifyAll(true) == IOPMAckImplied ) { // notify interested drivers and children
3243 our_prechange_1();
3244 }
3245 }
3246}
3247
3248
3249//*********************************************************************************
3250// ask_parent
3251//
3252// Call the power domain parent to ask for a higher power state in the domain
3253// or to suggest a lower power state.
3254//*********************************************************************************
3255
3256IOReturn IOService::ask_parent ( unsigned long requestedState )
3257{
0b4e3aa0
A
3258 OSIterator * iter;
3259 OSObject * next;
1c79356b 3260 IOPowerConnection * connection;
0b4e3aa0
A
3261 IOService * parent;
3262 unsigned long ourRequest = pm_vars->thePowerStates[requestedState].inputPowerRequirement;
1c79356b 3263
0b4e3aa0
A
3264 if ( pm_vars->thePowerStates[requestedState].capabilityFlags & (kIOPMChildClamp | kIOPMPreventIdleSleep) ) {
3265 ourRequest |= kIOPMPreventIdleSleep;
3266 }
3267 if ( pm_vars->thePowerStates[requestedState].capabilityFlags & (kIOPMChildClamp2 | kIOPMPreventSystemSleep) ) {
3268 ourRequest |= kIOPMPreventSystemSleep;
3269 }
3270
d7e50217
A
3271 // is this a new desire?
3272 if ( priv->previousRequest == ourRequest )
3273 {
3274 // no, the parent knows already, just return
3275 return IOPMNoErr;
1c79356b
A
3276 }
3277
3278 if ( priv->we_are_root ) {
3279 return IOPMNoErr;
3280 }
0b4e3aa0 3281 priv->previousRequest = ourRequest;
1c79356b
A
3282
3283 iter = getParentIterator(gIOPowerPlane);
3284
3285 if ( iter ) {
3286 while ( (next = iter->getNextObject()) ) {
3287 if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) {
0b4e3aa0
A
3288 parent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
3289 if ( parent ) {
3290 if ( parent->requestPowerDomainState(ourRequest,connection,IOPMLowestState)!= IOPMNoErr ) {
3291 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogRequestDenied,
3292 (unsigned long)priv->previousRequest,0);
3293 }
3294 parent->release();
1c79356b
A
3295 }
3296 }
3297 }
3298 iter->release();
3299 }
3300
3301 return IOPMNoErr;
3302}
3303
3304
3305//*********************************************************************************
3306// instruct_driver
3307//
3308// Call the controlling driver and have it change the power state of the
3309// hardware. If it returns IOPMAckImplied, the change is complete, and
3310// we return IOPMAckImplied. Otherwise, it will ack when the change
3311// is done; we return IOPMWillAckLater.
3312//*********************************************************************************
1c79356b
A
3313IOReturn IOService::instruct_driver ( unsigned long newState )
3314{
3315 IOReturn return_code;
3316
3317 if ( pm_vars->thePowerStates[newState].capabilityFlags & IOPMNotAttainable ) { // can our driver switch to the desired state?
3318 return IOPMAckImplied; // no, so don't try
3319 }
3320 priv->driver_timer = -1;
3321
3322 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogProgramHardware,newState,0);
0b4e3aa0 3323
9bccf70c 3324 ioSPMTraceStart(IOPOWER_STATE, * (int *) this, (int) newState);
0b4e3aa0 3325 return_code = pm_vars->theControllingDriver->setPowerState( newState,this ); // yes, instruct it
9bccf70c
A
3326 ioSPMTraceEnd(IOPOWER_STATE, * (int *) this, (int) newState, (int) return_code);
3327
1c79356b
A
3328 if ( return_code == IOPMAckImplied ) { // it finished
3329 priv->driver_timer = 0;
3330 return IOPMAckImplied;
3331 }
3332
3333 if ( priv->driver_timer == 0 ) { // it acked behind our back
3334 return IOPMAckImplied;
3335 }
3336
3337 if ( return_code < 0 ) { // somebody goofed
3338 return IOPMAckImplied;
3339 }
1c79356b
A
3340 priv->driver_timer = (return_code * ns_per_us / ACK_TIMER_PERIOD) + 1; // it didn't finish
3341 return IOPMWillAckLater;
3342}
3343
3344
3345//*********************************************************************************
3346// acquire_lock
3347//
3348// We are acquiring the lock we use to protect our queue head from
3349// simutaneous access by a thread which calls acknowledgePowerStateChange
3350// or acknowledgeSetPowerState and the ack timer expiration thread.
3351// Return TRUE if we acquire the lock, and the queue head didn't change
3352// while we were acquiring the lock (and maybe blocked).
3353// If there is no queue head, or it changes while we are blocked,
3354// return FALSE with the lock unlocked.
3355//*********************************************************************************
3356
3357bool IOService::acquire_lock ( void )
3358{
3359 long current_change_note;
3360
3361 current_change_note = priv->head_note;
3362 if ( current_change_note == -1 ) {
3363 return FALSE;
3364 }
3365
3366 IOTakeLock(priv->our_lock);
3367 if ( current_change_note == priv->head_note ) {
3368 return TRUE;
3369 }
3370 else { // we blocked and something changed radically
3371 IOUnlock(priv->our_lock); // so there's nothing to do any more
3372 return FALSE;
3373 }
3374}
3375
3376
3377//*********************************************************************************
3378// askChangeDown
3379//
3380// Ask registered applications and kernel clients if we can change to a lower
3381// power state.
3382//
3383// Subclass can override this to send a different message type. Parameter is
3384// the destination state number.
3385//
3386// Return true if we don't have to wait for acknowledgements
3387//*********************************************************************************
3388
0b4e3aa0 3389bool IOService::askChangeDown ( unsigned long stateNum )
1c79356b
A
3390{
3391 return tellClientsWithResponse(kIOMessageCanDevicePowerOff);
3392}
3393
3394
0b4e3aa0
A
3395//*********************************************************************************
3396// tellChangeDown1
3397//
3398// Notify registered applications and kernel clients that we are definitely
3399// dropping power.
3400//
3401// Return true if we don't have to wait for acknowledgements
3402//*********************************************************************************
3403
3404bool IOService::tellChangeDown1 ( unsigned long stateNum )
3405{
3406 pm_vars->outofbandparameter = kNotifyApps;
3407 return tellChangeDown(stateNum);
3408}
3409
3410
3411//*********************************************************************************
3412// tellChangeDown2
3413//
3414// Notify priority clients that we are definitely dropping power.
3415//
3416// Return true if we don't have to wait for acknowledgements
3417//*********************************************************************************
3418
3419bool IOService::tellChangeDown2 ( unsigned long stateNum )
3420{
3421 pm_vars->outofbandparameter = kNotifyPriority;
3422 return tellChangeDown(stateNum);
3423}
3424
3425
1c79356b
A
3426//*********************************************************************************
3427// tellChangeDown
3428//
3429// Notify registered applications and kernel clients that we are definitely
3430// dropping power.
3431//
3432// Subclass can override this to send a different message type. Parameter is
3433// the destination state number.
3434//
3435// Return true if we don't have to wait for acknowledgements
3436//*********************************************************************************
3437
0b4e3aa0 3438bool IOService::tellChangeDown ( unsigned long stateNum )
1c79356b
A
3439{
3440 return tellClientsWithResponse(kIOMessageDeviceWillPowerOff);
3441}
3442
3443
3444//*********************************************************************************
3445// tellClientsWithResponse
3446//
3447// Notify registered applications and kernel clients that we are definitely
3448// dropping power.
3449//
3450// Return true if we don't have to wait for acknowledgements
3451//*********************************************************************************
3452
3453bool IOService::tellClientsWithResponse ( int messageType )
3454{
3455 struct context theContext;
3456 AbsoluteTime deadline;
3457 OSBoolean * aBool;
3458
3459 pm_vars->responseFlags = OSArray::withCapacity( 1 );
3460 pm_vars->serialNumber += 1;
3461
3462 theContext.responseFlags = pm_vars->responseFlags;
3463 theContext.serialNumber = pm_vars->serialNumber;
3464 theContext.flags_lock = priv->flags_lock;
3465 theContext.counter = 1;
3466 theContext.msgType = messageType;
3467 theContext.us = this;
3468 theContext.maxTimeRequested = 0;
0b4e3aa0
A
3469 theContext.stateNumber = priv->head_note_state;
3470 theContext.stateFlags = priv->head_note_capabilityFlags;
3471
1c79356b
A
3472 IOLockLock(priv->flags_lock);
3473 aBool = OSBoolean::withBoolean(false); // position zero is false to
3474 theContext.responseFlags->setObject(0,aBool); // prevent allowCancelCommon from succeeding
3475 aBool->release();
3476 IOLockUnlock(priv->flags_lock);
3477
0b4e3aa0
A
3478 switch ( pm_vars->outofbandparameter ) {
3479 case kNotifyApps:
3480 applyToInterested(gIOAppPowerStateInterest,tellAppWithResponse,(void *)&theContext);
3481 applyToInterested(gIOGeneralInterest,tellClientWithResponse,(void *)&theContext);
3482 break;
3483 case kNotifyPriority:
3484 applyToInterested(gIOPriorityPowerStateInterest,tellClientWithResponse,(void *)&theContext);
3485 break;
3486 }
1c79356b
A
3487
3488 if (! acquire_lock() ) {
3489 return true;
3490 }
3491 IOLockLock(priv->flags_lock);
3492 aBool = OSBoolean::withBoolean(true); // now fix position zero
3493 theContext.responseFlags->replaceObject(0,aBool);
3494 aBool->release();
3495 IOLockUnlock(priv->flags_lock);
3496
3497 if ( ! checkForDone() ) { // we have to wait for somebody
3498 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogStartAckTimer,theContext.maxTimeRequested,0);
3499 clock_interval_to_deadline(theContext.maxTimeRequested / 1000, kMillisecondScale, &deadline);
3500
3501 thread_call_enter_delayed(priv->ackTimer, deadline);
3502
3503 IOUnlock(priv->our_lock); // yes
3504 return false;
3505 }
3506
3507 IOUnlock(priv->our_lock);
3508 IOLockLock(priv->flags_lock);
3509 pm_vars->responseFlags->release(); // everybody responded
3510 pm_vars->responseFlags = NULL;
3511 IOLockUnlock(priv->flags_lock);
3512
3513 return true;
3514}
3515
3516
3517//*********************************************************************************
3518// tellAppWithResponse
3519//
3520// We send a message to an application, and we expect a response, so we compute a
3521// cookie we can identify the response with.
3522//*********************************************************************************
3523void tellAppWithResponse ( OSObject * object, void * context)
3524{
3525 struct context * theContext = (struct context *)context;
3526 UInt32 refcon;
3527 OSBoolean * aBool;
3528
3529 if( OSDynamicCast( IOService, object) ) {
3530 IOLockLock(theContext->flags_lock);
3531 aBool = OSBoolean::withBoolean(true);
3532 theContext->responseFlags->setObject(theContext->counter,aBool);
3533 aBool->release();
3534 IOLockUnlock(theContext->flags_lock);
3535 }
3536 else {
3537 refcon = ((theContext->serialNumber & 0xFFFF)<<16) + (theContext->counter & 0xFFFF);
3538 IOLockLock(theContext->flags_lock);
3539 aBool = OSBoolean::withBoolean(false);
3540 theContext->responseFlags->setObject(theContext->counter,aBool);
3541 aBool->release();
3542 IOLockUnlock(theContext->flags_lock);
3543 theContext->us->messageClient(theContext->msgType,object,(void *)refcon);
0b4e3aa0
A
3544 if ( theContext->maxTimeRequested < k30seconds ) {
3545 theContext->maxTimeRequested = k30seconds;
1c79356b
A
3546 }
3547 }
3548 theContext->counter += 1;
3549}
3550
3551
3552//*********************************************************************************
3553// tellClientWithResponse
3554//
3555// We send a message to an in-kernel client, and we expect a response, so we compute a
3556// cookie we can identify the response with.
3557// If it doesn't understand the notification (it is not power-management savvy)
3558// we won't wait for it to prepare for sleep. If it tells us via a return code
3559// in the passed struct that it is currently ready, we won't wait for it to prepare.
3560// If it tells us via the return code in the struct that it does need time, we will chill.
3561//*********************************************************************************
3562void tellClientWithResponse ( OSObject * object, void * context)
3563{
0b4e3aa0
A
3564 struct context * theContext = (struct context *)context;
3565 IOPowerStateChangeNotification notify;
3566 UInt32 refcon;
3567 IOReturn retCode;
3568 OSBoolean * aBool;
3569 OSObject * theFlag;
1c79356b
A
3570
3571 refcon = ((theContext->serialNumber & 0xFFFF)<<16) + (theContext->counter & 0xFFFF);
3572 IOLockLock(theContext->flags_lock);
3573 aBool = OSBoolean::withBoolean(false);
3574 theContext->responseFlags->setObject(theContext->counter,aBool);
3575 aBool->release();
3576 IOLockUnlock(theContext->flags_lock);
0b4e3aa0
A
3577
3578 notify.powerRef = (void *)refcon;
3579 notify.returnValue = 0;
3580 notify.stateNumber = theContext->stateNumber;
3581 notify.stateFlags = theContext->stateFlags;
3582 retCode = theContext->us->messageClient(theContext->msgType,object,(void *)&notify);
1c79356b 3583 if ( retCode == kIOReturnSuccess ) {
0b4e3aa0 3584 if ( notify.returnValue == 0 ) { // client doesn't want time to respond
1c79356b
A
3585 IOLockLock(theContext->flags_lock);
3586 aBool = OSBoolean::withBoolean(true);
3587 theContext->responseFlags->replaceObject(theContext->counter,aBool); // so set its flag true
3588 aBool->release();
3589 IOLockUnlock(theContext->flags_lock);
3590 }
3591 else {
3592 IOLockLock(theContext->flags_lock);
3593 theFlag = theContext->responseFlags->getObject(theContext->counter); // it does want time, and it hasn't
3594 if ( theFlag != 0 ) { // responded yet
3595 if ( ((OSBoolean *)theFlag)->isFalse() ) { // so note its time requirement
0b4e3aa0
A
3596 if ( theContext->maxTimeRequested < notify.returnValue ) {
3597 theContext->maxTimeRequested = notify.returnValue;
1c79356b
A
3598 }
3599 }
3600 }
3601 IOLockUnlock(theContext->flags_lock);
3602 }
3603 }
3604 else { // not a client of ours
3605 IOLockLock(theContext->flags_lock);
3606 aBool = OSBoolean::withBoolean(true); // so we won't be waiting for response
3607 theContext->responseFlags->replaceObject(theContext->counter,aBool);
3608 aBool->release();
3609 IOLockUnlock(theContext->flags_lock);
3610 }
3611 theContext->counter += 1;
3612}
3613
3614
3615//*********************************************************************************
3616// tellNoChangeDown
3617//
3618// Notify registered applications and kernel clients that we are not
3619// dropping power.
3620//
3621// Subclass can override this to send a different message type. Parameter is
3622// the aborted destination state number.
3623//*********************************************************************************
3624
3625void IOService::tellNoChangeDown ( unsigned long )
3626{
3627 return tellClients(kIOMessageDeviceWillNotPowerOff);
3628}
3629
3630
3631//*********************************************************************************
3632// tellChangeUp
3633//
3634// Notify registered applications and kernel clients that we are raising power.
3635//
3636// Subclass can override this to send a different message type. Parameter is
3637// the aborted destination state number.
3638//*********************************************************************************
3639
3640void IOService::tellChangeUp ( unsigned long )
3641{
3642 return tellClients(kIOMessageDeviceHasPoweredOn);
3643}
3644
3645
3646//*********************************************************************************
3647// tellClients
3648//
3649// Notify registered applications and kernel clients of something.
3650//*********************************************************************************
3651
3652void IOService::tellClients ( int messageType )
3653{
3654 struct context theContext;
3655
3656 theContext.msgType = messageType;
3657 theContext.us = this;
0b4e3aa0
A
3658 theContext.stateNumber = priv->head_note_state;
3659 theContext.stateFlags = priv->head_note_capabilityFlags;
1c79356b
A
3660
3661 applyToInterested(gIOAppPowerStateInterest,tellClient,(void *)&theContext);
3662 applyToInterested(gIOGeneralInterest,tellClient,(void *)&theContext);
3663}
3664
3665
3666//*********************************************************************************
3667// tellClient
3668//
3669// Notify a registered application or kernel client of something.
3670//*********************************************************************************
3671void tellClient ( OSObject * object, void * context)
3672{
0b4e3aa0
A
3673 struct context * theContext = (struct context *)context;
3674 IOPowerStateChangeNotification notify;
1c79356b 3675
0b4e3aa0
A
3676 notify.powerRef = (void *) 0;
3677 notify.returnValue = 0;
3678 notify.stateNumber = theContext->stateNumber;
3679 notify.stateFlags = theContext->stateFlags;
3680
3681 theContext->us->messageClient(theContext->msgType,object, &notify);
1c79356b
A
3682}
3683
3684
3685// **********************************************************************************
3686// checkForDone
3687//
3688// **********************************************************************************
3689bool IOService::checkForDone ( void )
3690{
3691 int i = 0;
3692 OSObject * theFlag;
3693
3694 IOLockLock(priv->flags_lock);
3695 if ( pm_vars->responseFlags == NULL ) {
3696 IOLockUnlock(priv->flags_lock);
3697 return true;
3698 }
3699 for ( i = 0; ; i++ ) {
3700 theFlag = pm_vars->responseFlags->getObject(i);
3701 if ( theFlag == NULL ) {
3702 break;
3703 }
3704 if ( ((OSBoolean *)theFlag)->isFalse() ) {
3705 IOLockUnlock(priv->flags_lock);
3706 return false;
3707 }
3708 }
3709 IOLockUnlock(priv->flags_lock);
3710 return true;
3711}
3712
3713
3714// **********************************************************************************
3715// responseValid
3716//
3717// **********************************************************************************
3718bool IOService::responseValid ( unsigned long x )
3719{
3720 UInt16 serialComponent;
3721 UInt16 ordinalComponent;
3722 OSObject * theFlag;
3723 unsigned long refcon = (unsigned long)x;
3724 OSBoolean * aBool;
3725
3726 serialComponent = (refcon>>16) & 0xFFFF;
3727 ordinalComponent = refcon & 0xFFFF;
3728
3729 if ( serialComponent != pm_vars->serialNumber ) {
3730 return false;
3731 }
3732
3733 IOLockLock(priv->flags_lock);
3734 if ( pm_vars->responseFlags == NULL ) {
3735 IOLockUnlock(priv->flags_lock);
3736 return false;
3737 }
3738
3739 theFlag = pm_vars->responseFlags->getObject(ordinalComponent);
3740
3741 if ( theFlag == 0 ) {
3742 IOLockUnlock(priv->flags_lock);
3743 return false;
3744 }
3745
3746 if ( ((OSBoolean *)theFlag)->isFalse() ) {
3747 aBool = OSBoolean::withBoolean(true);
3748 pm_vars->responseFlags->replaceObject(ordinalComponent,aBool);
3749 aBool->release();
3750 }
3751
3752 IOLockUnlock(priv->flags_lock);
3753 return true;
3754}
3755
3756
3757// **********************************************************************************
3758// allowPowerChange
3759//
3760// Our power state is about to lower, and we have notified applications
3761// and kernel clients, and one of them has acknowledged. If this is the last to do
3762// so, and all acknowledgements are positive, we continue with the power change.
3763//
3764// We serialize this processing with timer expiration with a command gate on the
3765// power management workloop, which the timer expiration is command gated to as well.
3766// **********************************************************************************
3767IOReturn IOService::allowPowerChange ( unsigned long refcon )
3768{
3769 if ( ! initialized ) {
3770 return kIOReturnSuccess; // we're unloading
3771 }
3772
3773 return pm_vars->PMcommandGate->runAction(serializedAllowPowerChange,(void *)refcon);
3774}
3775
3776
3777IOReturn serializedAllowPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
3778{
3779 return ((IOService *)owner)->serializedAllowPowerChange2((unsigned long)refcon);
3780}
3781
3782IOReturn IOService::serializedAllowPowerChange2 ( unsigned long refcon )
3783{
3784 if ( ! responseValid(refcon) ) { // response valid?
3785 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr5,refcon,0);
3786 return kIOReturnSuccess; // no, just return
3787 }
3788 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientAcknowledge,refcon,0);
3789
3790 return allowCancelCommon();
3791}
3792
3793
3794// **********************************************************************************
3795// cancelPowerChange
3796//
3797// Our power state is about to lower, and we have notified applications
3798// and kernel clients, and one of them has vetoed the change. If this is the last
3799// client to respond, we abandon the power change.
3800//
3801// We serialize this processing with timer expiration with a command gate on the
3802// power management workloop, which the timer expiration is command gated to as well.
3803// **********************************************************************************
3804IOReturn IOService::cancelPowerChange ( unsigned long refcon )
3805{
3806 if ( ! initialized ) {
3807 return kIOReturnSuccess; // we're unloading
3808 }
3809
3810 return pm_vars->PMcommandGate->runAction(serializedCancelPowerChange,(void *)refcon);
3811}
3812
3813
3814IOReturn serializedCancelPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
3815{
3816 return ((IOService *)owner)->serializedCancelPowerChange2((unsigned long)refcon);
3817}
3818
3819IOReturn IOService::serializedCancelPowerChange2 ( unsigned long refcon )
3820{
3821 if ( ! responseValid(refcon) ) { // response valid?
3822 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogAcknowledgeErr5,refcon,0);
3823 return kIOReturnSuccess; // no, just return
3824 }
3825 pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogClientCancel,refcon,0);
3826
3827 pm_vars->doNotPowerDown = true;
3828
3829 return allowCancelCommon();
3830}
3831
3832
3833// **********************************************************************************
3834// allowCancelCommon
3835//
3836// **********************************************************************************
3837IOReturn IOService::allowCancelCommon ( void )
3838{
3839 if (! acquire_lock() ) {
3840 return kIOReturnSuccess;
3841 }
3842
3843 if ( checkForDone() ) { // is this the last response?
3844 stop_ack_timer(); // yes, stop the timer
3845 IOUnlock(priv->our_lock);
3846 IOLockLock(priv->flags_lock);
3847 if ( pm_vars->responseFlags ) {
3848 pm_vars->responseFlags->release();
3849 pm_vars->responseFlags = NULL;
3850 }
3851 IOLockUnlock(priv->flags_lock);
3852 switch (priv->machine_state) {
3853 case IOPMour_prechange_03: // our change, was it vetoed?
3854 if ( ! pm_vars->doNotPowerDown ) {
3855 our_prechange_03(); // no, we can continue
3856 }
3857 else {
3858 tellNoChangeDown(priv->head_note_state); // yes, rescind the warning
3859 priv->head_note_flags |= IOPMNotDone; // mark the change note un-actioned
3860 all_done(); // and we're done
3861 }
3862 break;
0b4e3aa0
A
3863 case IOPMour_prechange_04:
3864 our_prechange_04();
3865 break;
1c79356b
A
3866 case IOPMour_prechange_05:
3867 our_prechange_05(); // our change, continue
3868 break;
3869 case IOPMparent_down_0:
0b4e3aa0
A
3870 parent_down_04(); // parent change, continue
3871 break;
3872 case IOPMparent_down_05:
3873 parent_down_05(); // parent change, continue
1c79356b
A
3874 break;
3875 }
1c79356b
A
3876 }
3877
3878 IOUnlock(priv->our_lock); // not done yet
3879 return kIOReturnSuccess;
3880}
3881
3882
3883//*********************************************************************************
3884// clampPowerOn
3885//
3886// Set to highest available power state for a minimum of duration milliseconds
3887//*********************************************************************************
3888
3889#define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
3890
3891void IOService::clampPowerOn (unsigned long duration)
3892{
9bccf70c 3893/*
1c79356b
A
3894 changePowerStateToPriv (pm_vars->theNumberOfPowerStates-1);
3895
3896 if ( priv->clampTimerEventSrc == NULL ) {
3897 priv->clampTimerEventSrc = IOTimerEventSource::timerEventSource(this,
3898 c_PM_Clamp_Timer_Expired);
3899
3900 IOWorkLoop * workLoop = getPMworkloop ();
3901
3902 if ( !priv->clampTimerEventSrc || !workLoop ||
3903 ( workLoop->addEventSource( priv->clampTimerEventSrc) != kIOReturnSuccess) ) {
3904
3905 }
3906 }
3907
9bccf70c
A
3908 priv->clampTimerEventSrc->setTimeout(300*USEC_PER_SEC, USEC_PER_SEC);
3909*/
1c79356b
A
3910}
3911
3912//*********************************************************************************
3913// PM_Clamp_Timer_Expired
3914//
3915// called when clamp timer expires...set power state to 0.
3916//*********************************************************************************
3917
3918void IOService::PM_Clamp_Timer_Expired (void)
3919{
3920 if ( ! initialized ) {
3921 return; // we're unloading
3922 }
3923
3924 changePowerStateToPriv (0);
3925}
3926
3927//*********************************************************************************
3928// c_PM_clamp_Timer_Expired (C Func)
3929//
3930// Called when our clamp timer expires...we will call the object method.
3931//*********************************************************************************
3932
3933void c_PM_Clamp_Timer_Expired (OSObject * client, IOTimerEventSource *)
3934{
3935 if (client)
3936 ((IOService *)client)->PM_Clamp_Timer_Expired ();
3937}
3938
3939
3940//*********************************************************************************
3941// setPowerState
3942//
3943// Does nothing here. This should be implemented in a subclass driver.
3944//*********************************************************************************
3945
3946IOReturn IOService::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice )
3947{
3948 return IOPMNoErr;
3949}
3950
3951
3952//*********************************************************************************
3953// maxCapabilityForDomainState
3954//
3955// Finds the highest power state in the array whose input power
3956// requirement is equal to the input parameter. Where a more intelligent
3957// decision is possible, override this in the subclassed driver.
3958//*********************************************************************************
3959
3960unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
3961{
3962 int i;
3963
3964 if (pm_vars->theNumberOfPowerStates == 0 ) {
3965 return 0;
3966 }
3967 for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) {
0b4e3aa0 3968 if ( (domainState & pm_vars->thePowerStates[i].inputPowerRequirement) == pm_vars->thePowerStates[i].inputPowerRequirement ) {
1c79356b
A
3969 return i;
3970 }
3971 }
3972 return 0;
3973}
3974
3975
3976//*********************************************************************************
3977// initialPowerStateForDomainState
3978//
3979// Finds the highest power state in the array whose input power
3980// requirement is equal to the input parameter. Where a more intelligent
3981// decision is possible, override this in the subclassed driver.
3982//*********************************************************************************
3983
3984unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
3985{
3986 int i;
3987
3988 if (pm_vars->theNumberOfPowerStates == 0 ) {
3989 return 0;
3990 }
3991 for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) {
0b4e3aa0 3992 if ( (domainState & pm_vars->thePowerStates[i].inputPowerRequirement) == pm_vars->thePowerStates[i].inputPowerRequirement ) {
1c79356b
A
3993 return i;
3994 }
3995 }
3996 return 0;
3997}
3998
3999
4000//*********************************************************************************
4001// powerStateForDomainState
4002//
4003// Finds the highest power state in the array whose input power
4004// requirement is equal to the input parameter. Where a more intelligent
4005// decision is possible, override this in the subclassed driver.
4006//*********************************************************************************
4007
4008unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
4009{
4010 int i;
4011
4012 if (pm_vars->theNumberOfPowerStates == 0 ) {
4013 return 0;
4014 }
4015 for ( i = (pm_vars->theNumberOfPowerStates)-1; i >= 0; i-- ) {
0b4e3aa0 4016 if ( (domainState & pm_vars->thePowerStates[i].inputPowerRequirement) == pm_vars->thePowerStates[i].inputPowerRequirement ) {
1c79356b
A
4017 return i;
4018 }
4019 }
4020 return 0;
4021}
4022
4023
4024//*********************************************************************************
4025// didYouWakeSystem
4026//
4027// Does nothing here. This should be implemented in a subclass driver.
4028//*********************************************************************************
4029
4030bool IOService::didYouWakeSystem ( void )
4031{
4032 return false;
4033}
4034
4035
4036//*********************************************************************************
4037// powerStateWillChangeTo
4038//
4039// Does nothing here. This should be implemented in a subclass driver.
4040//*********************************************************************************
4041
4042IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService*)
4043{
4044 return 0;
4045}
4046
4047
4048//*********************************************************************************
4049// powerStateDidChangeTo
4050//
4051// Does nothing here. This should be implemented in a subclass driver.
4052//*********************************************************************************
4053
4054IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService*)
4055{
4056 return 0;
4057}
4058
4059
4060//*********************************************************************************
4061// powerChangeDone
4062//
4063// Does nothing here. This should be implemented in a subclass policy-maker.
4064//*********************************************************************************
4065
4066void IOService::powerChangeDone ( unsigned long )
4067{
4068}
4069
4070
4071//*********************************************************************************
4072// newTemperature
4073//
4074// Does nothing here. This should be implemented in a subclass driver.
4075//*********************************************************************************
4076
4077IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
4078
4079{
4080 return IOPMNoErr;
4081}
4082
4083
4084#undef super
4085#define super OSObject
4086
4087OSDefineMetaClassAndStructors(IOPMprot, OSObject)
4088//*********************************************************************************
4089// serialize
4090//
4091// Serialize protected instance variables for debug output.
4092//*********************************************************************************
4093bool IOPMprot::serialize(OSSerialize *s) const
4094{
4095 OSString * theOSString;
4096 char * buffer;
4097 char * ptr;
4098 int i;
4099 bool rtn_code;
4100
4101 buffer = ptr = IONew(char, 2000);
4102 if(!buffer)
4103 return false;
4104
4105 ptr += sprintf(ptr,"{ theNumberOfPowerStates = %d, ",(unsigned int)theNumberOfPowerStates);
4106
4107 if ( theNumberOfPowerStates != 0 ) {
4108 ptr += sprintf(ptr,"version %d, ",(unsigned int)thePowerStates[0].version);
4109 }
4110
4111 if ( theNumberOfPowerStates != 0 ) {
4112 for ( i = 0; i < (int)theNumberOfPowerStates; i++ ) {
4113 ptr += sprintf(ptr,"power state %d = { ",i);
4114 ptr += sprintf(ptr,"capabilityFlags %08x, ",(unsigned int)thePowerStates[i].capabilityFlags);
4115 ptr += sprintf(ptr,"outputPowerCharacter %08x, ",(unsigned int)thePowerStates[i].outputPowerCharacter);
4116 ptr += sprintf(ptr,"inputPowerRequirement %08x, ",(unsigned int)thePowerStates[i].inputPowerRequirement);
4117 ptr += sprintf(ptr,"staticPower %d, ",(unsigned int)thePowerStates[i].staticPower);
4118 ptr += sprintf(ptr,"unbudgetedPower %d, ",(unsigned int)thePowerStates[i].unbudgetedPower);
4119 ptr += sprintf(ptr,"powerToAttain %d, ",(unsigned int)thePowerStates[i].powerToAttain);
4120 ptr += sprintf(ptr,"timeToAttain %d, ",(unsigned int)thePowerStates[i].timeToAttain);
4121 ptr += sprintf(ptr,"settleUpTime %d, ",(unsigned int)thePowerStates[i].settleUpTime);
4122 ptr += sprintf(ptr,"timeToLower %d, ",(unsigned int)thePowerStates[i].timeToLower);
4123 ptr += sprintf(ptr,"settleDownTime %d, ",(unsigned int)thePowerStates[i].settleDownTime);
4124 ptr += sprintf(ptr,"powerDomainBudget %d }, ",(unsigned int)thePowerStates[i].powerDomainBudget);
4125 }
4126 }
4127
4128 ptr += sprintf(ptr,"aggressiveness = %d, ",(unsigned int)aggressiveness);
4129 ptr += sprintf(ptr,"myCurrentState = %d, ",(unsigned int)myCurrentState);
4130 ptr += sprintf(ptr,"parentsCurrentPowerFlags = %08x, ",(unsigned int)parentsCurrentPowerFlags);
4131 ptr += sprintf(ptr,"maxCapability = %d }",(unsigned int)maxCapability);
4132
4133 theOSString = OSString::withCString(buffer);
4134 rtn_code = theOSString->serialize(s);
4135 theOSString->release();
4136 IODelete(buffer, char, 2000);
4137
4138 return rtn_code;
4139}
4140
4141
4142#undef super
4143#define super OSObject
4144
4145OSDefineMetaClassAndStructors(IOPMpriv, OSObject)
4146//*********************************************************************************
4147// serialize
4148//
4149// Serialize private instance variables for debug output.
4150//*********************************************************************************
4151bool IOPMpriv::serialize(OSSerialize *s) const
4152{
4153 OSString * theOSString;
4154 bool rtn_code;
4155 char * buffer;
4156 char * ptr;
4157 IOPMinformee * nextObject;
4158
4159 buffer = ptr = IONew(char, 2000);
4160 if(!buffer)
4161 return false;
4162
4163 ptr += sprintf(ptr,"{ this object = %08x",(unsigned int)owner);
4164 if ( we_are_root ) {
4165 ptr += sprintf(ptr," (root)");
4166 }
4167 ptr += sprintf(ptr,", ");
4168
4169 nextObject = interestedDrivers->firstInList(); // display interested drivers
4170 while ( nextObject != NULL ) {
4171 ptr += sprintf(ptr,"interested driver = %08x, ",(unsigned int)nextObject->whatObject);
4172 nextObject = interestedDrivers->nextInList(nextObject);
4173 }
4174
4175 if ( machine_state != IOPMfinished ) {
4176 ptr += sprintf(ptr,"machine_state = %d, ",(unsigned int)machine_state);
4177 ptr += sprintf(ptr,"driver_timer = %d, ",(unsigned int)driver_timer);
4178 ptr += sprintf(ptr,"settle_time = %d, ",(unsigned int)settle_time);
4179 ptr += sprintf(ptr,"head_note_flags = %08x, ",(unsigned int)head_note_flags);
4180 ptr += sprintf(ptr,"head_note_state = %d, ",(unsigned int)head_note_state);
4181 ptr += sprintf(ptr,"head_note_outputFlags = %08x, ",(unsigned int)head_note_outputFlags);
4182 ptr += sprintf(ptr,"head_note_domainState = %08x, ",(unsigned int)head_note_domainState);
4183 ptr += sprintf(ptr,"head_note_capabilityFlags = %08x, ",(unsigned int)head_note_capabilityFlags);
4184 ptr += sprintf(ptr,"head_note_pendingAcks = %d, ",(unsigned int)head_note_pendingAcks);
4185 }
4186
4187 if ( device_overrides ) {
4188 ptr += sprintf(ptr,"device overrides, ");
4189 }
4190 ptr += sprintf(ptr,"driverDesire = %d, ",(unsigned int)driverDesire);
4191 ptr += sprintf(ptr,"deviceDesire = %d, ",(unsigned int)deviceDesire);
4192 ptr += sprintf(ptr,"ourDesiredPowerState = %d, ",(unsigned int)ourDesiredPowerState);
4193 ptr += sprintf(ptr,"previousRequest = %d }",(unsigned int)previousRequest);
4194
4195 theOSString = OSString::withCString(buffer);
4196 rtn_code = theOSString->serialize(s);
4197 theOSString->release();
4198 IODelete(buffer, char, 2000);
4199
4200 return rtn_code;
4201}
4202