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