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