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