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