]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOServicePM.cpp
xnu-1228.7.58.tar.gz
[apple/xnu.git] / iokit / Kernel / IOServicePM.cpp
1 /*
2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <IOKit/assert.h>
30 #include <IOKit/IOKitDebug.h>
31 #include <IOKit/IOLib.h>
32 #include <IOKit/IOMessage.h>
33 #include <IOKit/IOPlatformExpert.h>
34 #include <IOKit/IOService.h>
35 #include <IOKit/IOTimerEventSource.h>
36 #include <IOKit/IOWorkLoop.h>
37 #include <IOKit/IOCommand.h>
38
39 #include <IOKit/pwr_mgt/IOPMlog.h>
40 #include <IOKit/pwr_mgt/IOPMinformee.h>
41 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
42 #include <IOKit/pwr_mgt/IOPowerConnection.h>
43 #include <IOKit/pwr_mgt/RootDomain.h>
44
45 #include <sys/proc.h>
46
47 // Required for notification instrumentation
48 #include "IOServicePrivate.h"
49 #include "IOServicePMPrivate.h"
50 #include "IOKitKernelInternal.h"
51
52 static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
53 static void PM_idle_timer_expired(OSObject *, IOTimerEventSource *);
54 void tellAppWithResponse(OSObject * object, void * context) { /*empty*/ }
55 void tellClientWithResponse(OSObject * object, void * context) { /*empty*/ }
56 void tellClient(OSObject * object, void * context);
57 IOReturn serializedAllowPowerChange(OSObject *, void *, void *, void *, void *);
58
59 static uint64_t computeTimeDeltaNS( const AbsoluteTime * start )
60 {
61 AbsoluteTime now;
62 uint64_t nsec;
63
64 clock_get_uptime(&now);
65 SUB_ABSOLUTETIME(&now, start);
66 absolutetime_to_nanoseconds(now, &nsec);
67 return nsec;
68 }
69
70 OSDefineMetaClassAndStructors(IOPMprot, OSObject)
71
72 // log setPowerStates longer than (ns):
73 #define LOG_SETPOWER_TIMES (50ULL * 1000ULL * 1000ULL)
74 // log app responses longer than (ns):
75 #define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
76
77 //*********************************************************************************
78 // Globals
79 //*********************************************************************************
80
81 static bool gIOPMInitialized = false;
82 static IOItemCount gIOPMBusyCount = 0;
83 static IOWorkLoop * gIOPMWorkLoop = 0;
84 static IOPMRequestQueue * gIOPMRequestQueue = 0;
85 static IOPMRequestQueue * gIOPMReplyQueue = 0;
86 static IOPMRequestQueue * gIOPMFreeQueue = 0;
87
88 //*********************************************************************************
89 // Macros
90 //*********************************************************************************
91
92 #define PM_ERROR(x...) do { kprintf(x); IOLog(x); } while (false)
93 #define PM_DEBUG(x...) do { kprintf(x); } while (false)
94
95 #define PM_TRACE(x...) do { \
96 if (kIOLogDebugPower & gIOKitDebug) kprintf(x); } while (false)
97
98 #define PM_CONNECT(x...)
99
100 #define PM_ASSERT_IN_GATE(x) \
101 do { \
102 assert(gIOPMWorkLoop->inGate()); \
103 } while(false)
104
105 #define PM_LOCK() IOLockLock(fPMLock)
106 #define PM_UNLOCK() IOLockUnlock(fPMLock)
107
108 #define ns_per_us 1000
109 #define k30seconds (30*1000000)
110 #define kMinAckTimeoutTicks (10*1000000)
111 #define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
112 #define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
113 #define kPwrMgtKey "IOPowerManagement"
114
115 #define OUR_PMLog(t, a, b) \
116 do { fPlatform->PMLog( fName, t, a, b); } while(0)
117
118 #define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
119
120 //*********************************************************************************
121 // PM machine states
122 //*********************************************************************************
123
124 enum {
125 kIOPM_OurChangeTellClientsPowerDown = 1,
126 kIOPM_OurChangeTellPriorityClientsPowerDown = 2,
127 kIOPM_OurChangeNotifyInterestedDriversWillChange = 3,
128 kIOPM_OurChangeSetPowerState = 4,
129 kIOPM_OurChangeWaitForPowerSettle = 5,
130 kIOPM_OurChangeNotifyInterestedDriversDidChange = 6,
131 kIOPM_OurChangeFinish = 7,
132 kIOPM_ParentDownTellPriorityClientsPowerDown = 8,
133 kIOPM_ParentDownNotifyInterestedDriversWillChange = 9,
134 /* 10 not used */
135 kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange = 11,
136 kIOPM_ParentDownSetPowerState = 12,
137 kIOPM_ParentDownWaitForPowerSettle = 13,
138 kIOPM_ParentDownAcknowledgeChange = 14,
139 kIOPM_ParentUpSetPowerState = 15,
140 /* 16 not used */
141 kIOPM_ParentUpWaitForSettleTime = 17,
142 kIOPM_ParentUpNotifyInterestedDriversDidChange = 18,
143 kIOPM_ParentUpAcknowledgePowerChange = 19,
144 kIOPM_Finished = 20,
145 kIOPM_DriverThreadCallDone = 21,
146 kIOPM_NotifyChildrenDone = 22
147 };
148
149
150 /*
151 Power Management defines a few roles that drivers can play in their own,
152 and other drivers', power management. We briefly define those here.
153
154 Many drivers implement their policy maker and power controller within the same
155 IOService object, but that is not required.
156
157 == Policy Maker ==
158 * Virtual IOService PM methods a "policy maker" may implement
159 * maxCapabilityForDomainState()
160 * initialPowerStateForDomainState()
161 * powerStateForDomainState()
162
163 * Virtual IOService PM methods a "policy maker" may CALL
164 * PMinit()
165
166 == Power Controller ==
167 * Virtual IOService PM methods a "power controller" may implement
168 * setPowerState()
169
170 * Virtual IOService PM methods a "power controller" may CALL
171 * joinPMtree()
172 * registerPowerDriver()
173
174 =======================
175 There are two different kinds of power state changes.
176 * One is initiated by a subclassed device object which has either decided
177 to change power state, or its controlling driver has suggested it, or
178 some other driver wants to use the idle device and has asked it to become
179 usable.
180 * The second kind of power state change is initiated by the power domain
181 parent.
182 The two are handled through different code paths.
183
184 We maintain a queue of "change notifications," or change notes.
185 * Usually the queue is empty.
186 * When it isn't, usually there is one change note in it
187 * It's possible to have more than one power state change pending at one
188 time, so a queue is implemented.
189 Example:
190 * The subclass device decides it's idle and initiates a change to a lower
191 power state. This causes interested parties to be notified, but they
192 don't all acknowledge right away. This causes the change note to sit
193 in the queue until all the acks are received. During this time, the
194 device decides it isn't idle anymore and wants to raise power back up
195 again. This change can't be started, however, because the previous one
196 isn't complete yet, so the second one waits in the queue. During this
197 time, the parent decides to lower or raise the power state of the entire
198 power domain and notifies the device, and that notification goes into
199 the queue, too, and can't be actioned until the others are.
200
201 == SelfInitiated ==
202 This is how a power change initiated by the subclass device is handled:
203 -> First, all interested parties are notified of the change via their
204 powerStateWillChangeTo method. If they all don't acknowledge via return
205 code, then we have to wait. If they do, or when they finally all
206 acknowledge via our acknowledgePowerChange method, then we can continue.
207 -> We call the controlling driver, instructing it to change to the new state
208 -> Then we wait for power to settle. If there is no settling-time, or after
209 it has passed,
210 -> we notify interested parties again, this time via their
211 powerStateDidChangeTo methods.
212 -> When they have all acked, we're done.
213 If we lowered power and don't need the power domain to be in its current power
214 state, we suggest to the parent that it lower the power domain state.
215
216 == PowerDomainDownInitiated ==
217 How a change to a lower power domain state initiated by the parent is handled:
218 -> First, we figure out what power state we will be in when the new domain
219 state is reached.
220 -> Then all interested parties are notified that we are moving to that new
221 state.
222 -> When they have acknowledged, we call the controlling driver to assume
223 that state and we wait for power to settle.
224 -> Then we acknowledge our preparedness to our parent. When all its
225 interested parties have acknowledged,
226 -> it lowers power and then notifies its interested parties again.
227 -> When we get this call, we notify our interested parties that the power
228 state has changed, and when they have all acknowledged, we're done.
229
230 == PowerDomainUpInitiated ==
231 How a change to a higher power domain state initiated by the parent is handled:
232 -> We figure out what power state we will be in when the new domain state is
233 reached.
234 -> If it is different from our current state we acknowledge the parent.
235 -> When all the parent's interested parties have acknowledged, it raises
236 power in the domain and waits for power to settle.
237 -> Then it notifies everyone that the new state has been reached.
238 -> When we get this call, we call the controlling driver, instructing it to
239 assume the new state, and wait for power to settle.
240 -> Then we notify our interested parties. When they all acknowledge we are
241 done.
242
243 In either of the two power domain state cases above, it is possible that we
244 will not be changing state even though the domain is.
245 Examples:
246 * A change to a lower domain state may not affect us because we are already
247 in a low enough state,
248 * We will not take advantage of a change to a higher domain state, because
249 we have no need of the higher power. In such cases, there is nothing to
250 do but acknowledge the parent. So when the parent calls our
251 powerDomainWillChange method, and we decide that we will not be changing
252 state, we merely acknowledge the parent, via return code, and wait.
253 When the parent subsequently calls powerStateDidChange, we acknowledge again
254 via return code, and the change is complete.
255
256 == 4 Paths Through State Machine ==
257 Power state changes are processed in a state machine, and since there are four
258 varieties of power state changes, there are four major paths through the state
259 machine.
260
261 == 5. No Need To change ==
262 The fourth is nearly trivial. In this path, the parent is changing the domain
263 state, but we are not changing the device state. The change starts when the
264 parent calls powerDomainWillChange. All we do is acknowledge the parent. When
265 the parent calls powerStateDidChange, we acknowledge the parent again, and
266 we're done.
267
268 == 1. OurChange Down == XXX gvdl
269 The first is fairly simple. It starts:
270 * when a power domain child calls requestPowerDomainState and we decide to
271 change power states to accomodate the child,
272 * or if our power-controlling driver calls changePowerStateTo,
273 * or if some other driver which is using our device calls makeUsable,
274 * or if a subclassed object calls changePowerStateToPriv.
275 These are all power changes initiated by us, not forced upon us by the parent.
276
277 -> We start by notifying interested parties.
278 -> If they all acknowledge via return code, we can go on to state
279 "msSetPowerState".
280 -> Otherwise, we start the ack timer and wait for the stragglers to
281 acknowlege by calling acknowledgePowerChange.
282 -> We move on to state "msSetPowerState" when all the
283 stragglers have acknowledged, or when the ack timer expires on
284 all those which didn't acknowledge.
285 In "msSetPowerState" we call the power-controlling driver to change the
286 power state of the hardware.
287 -> If it returns saying it has done so, we go on to state
288 "msWaitForPowerSettle".
289 -> Otherwise, we have to wait for it, so we set the ack timer and wait.
290 -> When it calls acknowledgeSetPowerState, or when the ack timer
291 expires, we go on.
292 In "msWaitForPowerSettle", we look in the power state array to see if
293 there is any settle time required when changing from our current state to the
294 new state.
295 -> If not, we go right away to "msNotifyInterestedDriversDidChange".
296 -> Otherwise, we set the settle timer and wait. When it expires, we move on.
297 In "msNotifyInterestedDriversDidChange" state, we notify all our
298 interested parties via their powerStateDidChange methods that we have finished
299 changing power state.
300 -> If they all acknowledge via return code, we move on to "msFinish".
301 -> Otherwise we set the ack timer and wait. When they have all
302 acknowledged, or when the ack timer has expired for those that didn't,
303 we move on to "msFinish".
304 In "msFinish" we remove the used change note from the head of the queue
305 and start the next one if one exists.
306
307 == 2. Parent Change Down ==
308 Start at Stage 2 of OurChange Down XXX gvdl
309
310 == 3. Change Up ==
311 Start at Stage 4 of OurChange Down XXX gvdl
312
313 Note all parent requested changes need to acknowledge the power has changed to the parent when done.
314 */
315
316 //*********************************************************************************
317 // [public virtual] PMinit
318 //
319 // Initialize power management.
320 //*********************************************************************************
321
322 void IOService::PMinit ( void )
323 {
324 if ( !initialized )
325 {
326 if ( !gIOPMInitialized )
327 {
328 gIOPMWorkLoop = IOWorkLoop::workLoop();
329 if (gIOPMWorkLoop)
330 {
331 gIOPMRequestQueue = IOPMRequestQueue::create(
332 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
333 this, &IOService::servicePMRequestQueue));
334
335 gIOPMReplyQueue = IOPMRequestQueue::create(
336 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
337 this, &IOService::servicePMReplyQueue));
338
339 gIOPMFreeQueue = IOPMRequestQueue::create(
340 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
341 this, &IOService::servicePMFreeQueue));
342
343 if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
344 kIOReturnSuccess)
345 {
346 gIOPMRequestQueue->release();
347 gIOPMRequestQueue = 0;
348 }
349
350 if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
351 kIOReturnSuccess)
352 {
353 gIOPMReplyQueue->release();
354 gIOPMReplyQueue = 0;
355 }
356
357 if (gIOPMWorkLoop->addEventSource(gIOPMFreeQueue) !=
358 kIOReturnSuccess)
359 {
360 gIOPMFreeQueue->release();
361 gIOPMFreeQueue = 0;
362 }
363 }
364
365 if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMFreeQueue)
366 gIOPMInitialized = true;
367 }
368 if (!gIOPMInitialized)
369 return;
370
371 pwrMgt = new IOServicePM;
372 pwrMgt->init();
373 setProperty(kPwrMgtKey, pwrMgt);
374
375 fOwner = this;
376 fWeAreRoot = false;
377 fPMLock = IOLockAlloc();
378 fInterestedDrivers = new IOPMinformeeList;
379 fInterestedDrivers->initialize();
380 fDesiredPowerState = 0;
381 fDriverDesire = 0;
382 fDeviceDesire = 0;
383 fInitialChange = true;
384 fNeedToBecomeUsable = false;
385 fPreviousRequest = 0;
386 fDeviceOverrides = false;
387 fMachineState = kIOPM_Finished;
388 fIdleTimerEventSource = NULL;
389 fIdleTimerMinPowerState = 0;
390 fActivityLock = IOLockAlloc();
391 fClampOn = false;
392 fStrictTreeOrder = false;
393 fActivityTicklePowerState = -1;
394 fControllingDriver = NULL;
395 fPowerStates = NULL;
396 fNumberOfPowerStates = 0;
397 fCurrentPowerState = 0;
398 fParentsCurrentPowerFlags = 0;
399 fMaxCapability = 0;
400 fName = getName();
401 fPlatform = getPlatform();
402 fParentsKnowState = false;
403 fSerialNumber = 0;
404 fResponseArray = NULL;
405 fDoNotPowerDown = true;
406 fCurrentPowerConsumption = kIOPMUnknown;
407
408 for (unsigned int i = 0; i <= kMaxType; i++)
409 {
410 fAggressivenessValue[i] = 0;
411 fAggressivenessValid[i] = false;
412 }
413
414 fAckTimer = thread_call_allocate(
415 &IOService::ack_timer_expired, (thread_call_param_t)this);
416 fSettleTimer = thread_call_allocate(
417 &settle_timer_expired, (thread_call_param_t)this);
418 fDriverCallEntry = thread_call_allocate(
419 (thread_call_func_t) &IOService::pmDriverCallout, this);
420 assert(fDriverCallEntry);
421
422 #if PM_VARS_SUPPORT
423 IOPMprot * prot = new IOPMprot;
424 if (prot)
425 {
426 prot->init();
427 prot->ourName = fName;
428 prot->thePlatform = fPlatform;
429 fPMVars = prot;
430 pm_vars = prot;
431 }
432 #else
433 pm_vars = (IOPMprot *) true;
434 #endif
435
436 initialized = true;
437 }
438 }
439
440 //*********************************************************************************
441 // [public] PMfree
442 //
443 // Free up the data created in PMinit, if it exists.
444 //*********************************************************************************
445
446 void IOService::PMfree ( void )
447 {
448 initialized = false;
449 pm_vars = 0;
450
451 if ( pwrMgt )
452 {
453 assert(fMachineState == kIOPM_Finished);
454 assert(fInsertInterestSet == NULL);
455 assert(fRemoveInterestSet == NULL);
456 assert(fNotifyChildArray == NULL);
457
458 if ( fIdleTimerEventSource != NULL ) {
459 getPMworkloop()->removeEventSource(fIdleTimerEventSource);
460 fIdleTimerEventSource->release();
461 fIdleTimerEventSource = NULL;
462 }
463 if ( fSettleTimer ) {
464 thread_call_cancel(fSettleTimer);
465 thread_call_free(fSettleTimer);
466 fSettleTimer = NULL;
467 }
468 if ( fAckTimer ) {
469 thread_call_cancel(fAckTimer);
470 thread_call_free(fAckTimer);
471 fAckTimer = NULL;
472 }
473 if ( fDriverCallEntry ) {
474 thread_call_free(fDriverCallEntry);
475 fDriverCallEntry = NULL;
476 }
477 if ( fPMLock ) {
478 IOLockFree(fPMLock);
479 fPMLock = NULL;
480 }
481 if ( fActivityLock ) {
482 IOLockFree(fActivityLock);
483 fActivityLock = NULL;
484 }
485 if ( fInterestedDrivers ) {
486 fInterestedDrivers->release();
487 fInterestedDrivers = NULL;
488 }
489 if ( fPMWorkQueue ) {
490 getPMworkloop()->removeEventSource(fPMWorkQueue);
491 fPMWorkQueue->release();
492 fPMWorkQueue = 0;
493 }
494 if (fDriverCallParamSlots && fDriverCallParamPtr) {
495 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
496 fDriverCallParamPtr = 0;
497 fDriverCallParamSlots = 0;
498 }
499 if ( fResponseArray ) {
500 fResponseArray->release();
501 fResponseArray = NULL;
502 }
503 if (fPowerStates && fNumberOfPowerStates) {
504 IODelete(fPowerStates, IOPMPowerState, fNumberOfPowerStates);
505 fNumberOfPowerStates = 0;
506 fPowerStates = NULL;
507 }
508
509 #if PM_VARS_SUPPORT
510 if (fPMVars)
511 {
512 fPMVars->release();
513 fPMVars = 0;
514 }
515 #endif
516
517 pwrMgt->release();
518 pwrMgt = 0;
519 }
520 }
521
522 //*********************************************************************************
523 // [public virtual] joinPMtree
524 //
525 // A policy-maker calls its nub here when initializing, to be attached into
526 // the power management hierarchy. The default function is to call the
527 // platform expert, which knows how to do it. This method is overridden
528 // by a nub subclass which may either know how to do it, or may need to
529 // take other action.
530 //
531 // This may be the only "power management" method used in a nub,
532 // meaning it may not be initialized for power management.
533 //*********************************************************************************
534
535 void IOService::joinPMtree ( IOService * driver )
536 {
537 IOPlatformExpert * platform;
538
539 platform = getPlatform();
540 assert(platform != 0);
541 platform->PMRegisterDevice(this, driver);
542 }
543
544 //*********************************************************************************
545 // [public virtual] youAreRoot
546 //
547 // Power Managment is informing us that we are the root power domain.
548 // The only difference between us and any other power domain is that
549 // we have no parent and therefore never call it.
550 //*********************************************************************************
551
552 IOReturn IOService::youAreRoot ( void )
553 {
554 fWeAreRoot = true;
555 fParentsKnowState = true;
556 attachToParent( getRegistryRoot(), gIOPowerPlane );
557 return IOPMNoErr;
558 }
559
560 //*********************************************************************************
561 // [public virtual] PMstop
562 //
563 // Immediately stop driver callouts. Schedule an async stop request to detach
564 // from power plane.
565 //*********************************************************************************
566
567 void IOService::PMstop ( void )
568 {
569 IOPMRequest * request;
570
571 if (!initialized)
572 return;
573
574 // Schedule an async PMstop request, but immediately stop any further
575 // calls to the controlling or interested drivers. This device will
576 // continue to exist in the power plane and participate in power state
577 // changes until the PMstop async request is processed.
578
579 PM_LOCK();
580 fWillPMStop = true;
581 if (fDriverCallBusy)
582 PM_DEBUG("%s::PMstop() driver call busy\n", getName());
583 PM_UNLOCK();
584
585 request = acquirePMRequest( this, kIOPMRequestTypePMStop );
586 if (request)
587 {
588 PM_TRACE("[%s] %p PMstop\n", getName(), this);
589 submitPMRequest( request );
590 }
591 }
592
593 //*********************************************************************************
594 // handlePMstop
595 //
596 // Disconnect the node from its parents and children in the Power Plane.
597 //*********************************************************************************
598
599 void IOService::handlePMstop ( IOPMRequest * request )
600 {
601 OSIterator * iter;
602 OSObject * next;
603 IOPowerConnection * connection;
604 IOService * theChild;
605 IOService * theParent;
606
607 PM_ASSERT_IN_GATE();
608 PM_TRACE("[%s] %p %s start\n", getName(), this, __FUNCTION__);
609
610 // remove the property
611 removeProperty(kPwrMgtKey);
612
613 // detach parents
614 iter = getParentIterator(gIOPowerPlane);
615 if ( iter )
616 {
617 while ( (next = iter->getNextObject()) )
618 {
619 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
620 {
621 theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
622 if ( theParent )
623 {
624 theParent->removePowerChild(connection);
625 theParent->release();
626 }
627 }
628 }
629 iter->release();
630 }
631
632 // detach IOConnections
633 detachAbove( gIOPowerPlane );
634
635 // no more power state changes
636 fParentsKnowState = false;
637
638 // detach children
639 iter = getChildIterator(gIOPowerPlane);
640 if ( iter )
641 {
642 while ( (next = iter->getNextObject()) )
643 {
644 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
645 {
646 theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
647 if ( theChild )
648 {
649 // detach nub from child
650 connection->detachFromChild(theChild, gIOPowerPlane);
651 theChild->release();
652 }
653 // detach us from nub
654 detachFromChild(connection, gIOPowerPlane);
655 }
656 }
657 iter->release();
658 }
659
660 // Remove all interested drivers from the list, including the power
661 // controlling driver.
662 //
663 // Usually, the controlling driver and the policy-maker functionality
664 // are implemented by the same object, and without the deregistration,
665 // the object will be holding an extra retain on itself, and cannot
666 // be freed.
667
668 if ( fInterestedDrivers )
669 {
670 IOPMinformeeList * list = fInterestedDrivers;
671 IOPMinformee * item;
672
673 PM_LOCK();
674 while ((item = list->firstInList()))
675 {
676 list->removeFromList(item->whatObject);
677 }
678 PM_UNLOCK();
679 }
680
681 // Tell PM_idle_timer_expiration() to ignore idle timer.
682 fIdleTimerPeriod = 0;
683
684 fWillPMStop = false;
685 PM_TRACE("[%s] %p %s done\n", getName(), this, __FUNCTION__);
686 }
687
688 //*********************************************************************************
689 // [public virtual] addPowerChild
690 //
691 // Power Management is informing us who our children are.
692 //*********************************************************************************
693
694 IOReturn IOService::addPowerChild ( IOService * child )
695 {
696 IOPowerConnection * connection = 0;
697 IOPMRequest * requests[3] = {0, 0, 0};
698 OSIterator * iter;
699 bool ok = true;
700
701 if (!child)
702 return kIOReturnBadArgument;
703
704 if (!initialized || !child->initialized)
705 return IOPMNotYetInitialized;
706
707 OUR_PMLog( kPMLogAddChild, 0, 0 );
708
709 do {
710 // Is this child already one of our children?
711
712 iter = child->getParentIterator( gIOPowerPlane );
713 if ( iter )
714 {
715 IORegistryEntry * entry;
716 OSObject * next;
717
718 while ((next = iter->getNextObject()))
719 {
720 if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
721 isChild(entry, gIOPowerPlane))
722 {
723 ok = false;
724 break;
725 }
726 }
727 iter->release();
728 }
729 if (!ok)
730 {
731 PM_DEBUG("[%s] %s (%p) is already a child\n",
732 getName(), child->getName(), child);
733 break;
734 }
735
736 // Add the child to the power plane immediately, but the
737 // joining connection is marked as not ready.
738 // We want the child to appear in the power plane before
739 // returning to the caller, but don't want the caller to
740 // block on the PM work loop.
741
742 connection = new IOPowerConnection;
743 if (!connection)
744 break;
745
746 // Create a chain of PM requests to perform the bottom-half
747 // work from the PM work loop.
748
749 requests[0] = acquirePMRequest(
750 /* target */ this,
751 /* type */ kIOPMRequestTypeAddPowerChild1 );
752
753 requests[1] = acquirePMRequest(
754 /* target */ child,
755 /* type */ kIOPMRequestTypeAddPowerChild2 );
756
757 requests[2] = acquirePMRequest(
758 /* target */ this,
759 /* type */ kIOPMRequestTypeAddPowerChild3 );
760
761 if (!requests[0] || !requests[1] || !requests[2])
762 break;
763
764 requests[0]->setParentRequest( requests[1] );
765 requests[1]->setParentRequest( requests[2] );
766
767 connection->init();
768 connection->start(this);
769 connection->setAwaitingAck(false);
770 connection->setReadyFlag(false);
771
772 attachToChild( connection, gIOPowerPlane );
773 connection->attachToChild( child, gIOPowerPlane );
774
775 // connection needs to be released
776 requests[0]->fArg0 = connection;
777 requests[1]->fArg0 = connection;
778 requests[2]->fArg0 = connection;
779
780 submitPMRequest( requests, 3 );
781 return kIOReturnSuccess;
782 }
783 while (false);
784
785 if (connection) connection->release();
786 if (requests[0]) releasePMRequest(requests[0]);
787 if (requests[1]) releasePMRequest(requests[1]);
788 if (requests[2]) releasePMRequest(requests[2]);
789
790 // silent failure, to prevent platform drivers from adding the child
791 // to the root domain.
792 return IOPMNoErr;
793 }
794
795 //*********************************************************************************
796 // [private] addPowerChild1
797 //
798 // Called on the power parent.
799 //*********************************************************************************
800
801 void IOService::addPowerChild1 ( IOPMRequest * request )
802 {
803 unsigned long tempDesire = 0;
804
805 // Make us temporary usable before adding the child.
806
807 PM_ASSERT_IN_GATE();
808 OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, fDeviceDesire );
809
810 if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
811 {
812 tempDesire = fNumberOfPowerStates - 1;
813 }
814
815 if (tempDesire && (fWeAreRoot || (fMaxCapability >= tempDesire)))
816 {
817 computeDesiredState( tempDesire );
818 changeState();
819 }
820 }
821
822 //*********************************************************************************
823 // [private] addPowerChild2
824 //
825 // Called on the joining child. Blocked behind addPowerChild1.
826 //*********************************************************************************
827
828 void IOService::addPowerChild2 ( IOPMRequest * request )
829 {
830 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
831 IOService * parent;
832 IOPMPowerFlags powerFlags;
833 bool knowsState;
834 unsigned long powerState;
835 unsigned long tempDesire;
836
837 PM_ASSERT_IN_GATE();
838 parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
839
840 if (!parent || !inPlane(gIOPowerPlane))
841 {
842 PM_DEBUG("[%s] addPowerChild2 not in power plane\n", getName());
843 return;
844 }
845
846 // Parent will be waiting for us to complete this stage, safe to
847 // directly access parent's vars.
848
849 knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
850 powerState = parent->fCurrentPowerState;
851
852 if (knowsState)
853 powerFlags = parent->fPowerStates[powerState].outputPowerCharacter;
854 else
855 powerFlags = 0;
856
857 // Set our power parent.
858
859 OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
860
861 setParentInfo( powerFlags, connection, knowsState );
862
863 connection->setReadyFlag(true);
864
865 if ( fControllingDriver && fParentsKnowState )
866 {
867 fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
868 // initially change into the state we are already in
869 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
870 computeDesiredState(tempDesire);
871 fPreviousRequest = 0xffffffff;
872 changeState();
873 }
874 }
875
876 //*********************************************************************************
877 // [private] addPowerChild3
878 //
879 // Called on the parent. Blocked behind addPowerChild2.
880 //*********************************************************************************
881
882 void IOService::addPowerChild3 ( IOPMRequest * request )
883 {
884 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
885 IOService * child;
886 unsigned int i;
887
888 PM_ASSERT_IN_GATE();
889 child = (IOService *) connection->getChildEntry(gIOPowerPlane);
890
891 if (child && inPlane(gIOPowerPlane))
892 {
893 if (child->getProperty("IOPMStrictTreeOrder"))
894 {
895 PM_DEBUG("[%s] strict ordering enforced\n", getName());
896 fStrictTreeOrder = true;
897 }
898
899 for (i = 0; i <= kMaxType; i++)
900 {
901 if ( fAggressivenessValid[i] )
902 {
903 child->setAggressiveness(i, fAggressivenessValue[i]);
904 }
905 }
906 }
907 else
908 {
909 PM_DEBUG("[%s] addPowerChild3 not in power plane\n", getName());
910 }
911
912 connection->release();
913 }
914
915 //*********************************************************************************
916 // [public virtual deprecated] setPowerParent
917 //
918 // Power Management is informing us who our parent is.
919 // If we have a controlling driver, find out, given our newly-informed
920 // power domain state, what state it would be in, and then tell it
921 // to assume that state.
922 //*********************************************************************************
923
924 IOReturn IOService::setPowerParent (
925 IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
926 {
927 return kIOReturnUnsupported;
928 }
929
930 //*********************************************************************************
931 // [public virtual] removePowerChild
932 //
933 // Called on a parent whose child is being removed by PMstop().
934 //*********************************************************************************
935
936 IOReturn IOService::removePowerChild ( IOPowerConnection * theNub )
937 {
938 IORegistryEntry * theChild;
939
940 PM_ASSERT_IN_GATE();
941 OUR_PMLog( kPMLogRemoveChild, 0, 0 );
942
943 theNub->retain();
944
945 // detach nub from child
946 theChild = theNub->copyChildEntry(gIOPowerPlane);
947 if ( theChild )
948 {
949 theNub->detachFromChild(theChild, gIOPowerPlane);
950 theChild->release();
951 }
952 // detach from the nub
953 detachFromChild(theNub, gIOPowerPlane);
954
955 // Are we awaiting an ack from this child?
956 if ( theNub->getAwaitingAck() )
957 {
958 // yes, pretend we got one
959 theNub->setAwaitingAck(false);
960 if (fHeadNotePendingAcks != 0 )
961 {
962 // that's one fewer ack to worry about
963 fHeadNotePendingAcks--;
964
965 // is that the last?
966 if ( fHeadNotePendingAcks == 0 )
967 {
968 stop_ack_timer();
969 }
970 }
971 }
972
973 theNub->release();
974
975 // Schedule a request to re-scan child desires and clamp bits.
976 if (!fWillAdjustPowerState)
977 {
978 IOPMRequest * request;
979
980 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
981 if (request)
982 {
983 submitPMRequest( request );
984 fWillAdjustPowerState = true;
985 }
986 }
987
988 return IOPMNoErr;
989 }
990
991 //*********************************************************************************
992 // [public virtual] registerPowerDriver
993 //
994 // A driver has called us volunteering to control power to our device.
995 //*********************************************************************************
996
997 IOReturn IOService::registerPowerDriver (
998 IOService * powerDriver,
999 IOPMPowerState * powerStates,
1000 unsigned long numberOfStates )
1001 {
1002 IOPMRequest * request;
1003 IOPMPowerState * powerStatesCopy = 0;
1004
1005 if (!initialized)
1006 return IOPMNotYetInitialized;
1007
1008 // Validate arguments.
1009 if (!powerStates || (numberOfStates < 2))
1010 {
1011 OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1012 return kIOReturnBadArgument;
1013 }
1014
1015 if (!powerDriver)
1016 {
1017 OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1018 return kIOReturnBadArgument;
1019 }
1020
1021 if (powerStates[0].version != kIOPMPowerStateVersion1)
1022 {
1023 OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1024 return kIOReturnBadArgument;
1025 }
1026
1027 do {
1028 // Make a copy of the supplied power state array.
1029 powerStatesCopy = IONew(IOPMPowerState, numberOfStates);
1030 if (!powerStatesCopy)
1031 break;
1032
1033 bcopy( powerStates, powerStatesCopy,
1034 sizeof(IOPMPowerState) * numberOfStates );
1035
1036 request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1037 if (!request)
1038 break;
1039
1040 powerDriver->retain();
1041 request->fArg0 = (void *) powerDriver;
1042 request->fArg1 = (void *) powerStatesCopy;
1043 request->fArg2 = (void *) numberOfStates;
1044
1045 submitPMRequest( request );
1046 return kIOReturnSuccess;
1047 }
1048 while (false);
1049
1050 if (powerStatesCopy)
1051 IODelete(powerStatesCopy, IOPMPowerState, numberOfStates);
1052 return kIOReturnNoMemory;
1053 }
1054
1055 //*********************************************************************************
1056 // [private] handleRegisterPowerDriver
1057 //*********************************************************************************
1058
1059 void IOService::handleRegisterPowerDriver ( IOPMRequest * request )
1060 {
1061 IOService * powerDriver = (IOService *) request->fArg0;
1062 IOPMPowerState * powerStates = (IOPMPowerState *) request->fArg1;
1063 unsigned long numberOfStates = (unsigned long) request->fArg2;
1064 unsigned long i;
1065 IOService * root;
1066
1067 PM_ASSERT_IN_GATE();
1068 assert(powerStates);
1069 assert(powerDriver);
1070 assert(numberOfStates > 1);
1071
1072 if ( !fNumberOfPowerStates )
1073 {
1074 OUR_PMLog(kPMLogControllingDriver,
1075 (unsigned long) numberOfStates,
1076 (unsigned long) powerStates[0].version);
1077
1078 fPowerStates = powerStates;
1079 fNumberOfPowerStates = numberOfStates;
1080 fControllingDriver = powerDriver;
1081 fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1082
1083 // make a mask of all the character bits we know about
1084 fOutputPowerCharacterFlags = 0;
1085 for ( i = 0; i < numberOfStates; i++ ) {
1086 fOutputPowerCharacterFlags |= fPowerStates[i].outputPowerCharacter;
1087 }
1088
1089 // Register powerDriver as interested, unless already done.
1090 // We don't want to register the default implementation since
1091 // it does nothing. One ramification of not always registering
1092 // is the one fewer retain count held.
1093
1094 root = getPlatform()->getProvider();
1095 assert(root);
1096 if (!root ||
1097 ((OSMemberFunctionCast(void (*)(void),
1098 root, &IOService::powerStateDidChangeTo)) !=
1099 ((OSMemberFunctionCast(void (*)(void),
1100 this, &IOService::powerStateDidChangeTo)))) ||
1101 ((OSMemberFunctionCast(void (*)(void),
1102 root, &IOService::powerStateWillChangeTo)) !=
1103 ((OSMemberFunctionCast(void (*)(void),
1104 this, &IOService::powerStateWillChangeTo)))))
1105 {
1106 if (fInterestedDrivers->findItem(powerDriver) == NULL)
1107 {
1108 PM_LOCK();
1109 fInterestedDrivers->appendNewInformee(powerDriver);
1110 PM_UNLOCK();
1111 }
1112 }
1113
1114 if ( fNeedToBecomeUsable ) {
1115 fNeedToBecomeUsable = false;
1116 fDeviceDesire = fNumberOfPowerStates - 1;
1117 }
1118
1119 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
1120 {
1121 unsigned long tempDesire;
1122 fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1123 // initially change into the state we are already in
1124 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1125 computeDesiredState(tempDesire);
1126 changeState();
1127 }
1128 }
1129 else
1130 {
1131 OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
1132 IODelete(powerStates, IOPMPowerState, numberOfStates);
1133 }
1134
1135 powerDriver->release();
1136 }
1137
1138 //*********************************************************************************
1139 // [public virtual] registerInterestedDriver
1140 //
1141 // Add the caller to our list of interested drivers and return our current
1142 // power state. If we don't have a power-controlling driver yet, we will
1143 // call this interested driver again later when we do get a driver and find
1144 // out what the current power state of the device is.
1145 //*********************************************************************************
1146
1147 IOPMPowerFlags IOService::registerInterestedDriver ( IOService * driver )
1148 {
1149 IOPMRequest * request;
1150 bool signal;
1151
1152 if (!initialized || !fInterestedDrivers)
1153 return IOPMNotPowerManaged;
1154
1155 PM_LOCK();
1156 signal = (!fInsertInterestSet && !fRemoveInterestSet);
1157 if (fInsertInterestSet == NULL)
1158 fInsertInterestSet = OSSet::withCapacity(4);
1159 if (fInsertInterestSet)
1160 fInsertInterestSet->setObject(driver);
1161 PM_UNLOCK();
1162
1163 if (signal)
1164 {
1165 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1166 if (request)
1167 submitPMRequest( request );
1168 }
1169
1170 // This return value cannot be trusted, but return a value
1171 // for those clients that care.
1172
1173 OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1174 return kIOPMDeviceUsable;
1175 }
1176
1177 //*********************************************************************************
1178 // [public virtual] deRegisterInterestedDriver
1179 //*********************************************************************************
1180
1181 IOReturn IOService::deRegisterInterestedDriver ( IOService * driver )
1182 {
1183 IOPMinformeeList * list;
1184 IOPMinformee * item;
1185 IOPMRequest * request;
1186 bool signal;
1187
1188 if (!initialized || !fInterestedDrivers)
1189 return IOPMNotPowerManaged;
1190
1191 PM_LOCK();
1192 signal = (!fRemoveInterestSet && !fInsertInterestSet);
1193 if (fRemoveInterestSet == NULL)
1194 fRemoveInterestSet = OSSet::withCapacity(4);
1195 if (fRemoveInterestSet)
1196 {
1197 fRemoveInterestSet->setObject(driver);
1198
1199 list = fInterestedDrivers;
1200 item = list->findItem(driver);
1201 if (item && item->active)
1202 {
1203 item->active = false;
1204 }
1205 if (fDriverCallBusy)
1206 PM_DEBUG("%s::deRegisterInterestedDriver() driver call busy\n", getName());
1207 }
1208 PM_UNLOCK();
1209
1210 if (signal)
1211 {
1212 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1213 if (request)
1214 submitPMRequest( request );
1215 }
1216
1217 return IOPMNoErr;
1218 }
1219
1220 //*********************************************************************************
1221 // [private] handleInterestChanged
1222 //
1223 // Handle interest added or removed.
1224 //*********************************************************************************
1225
1226 void IOService::handleInterestChanged( IOPMRequest * request )
1227 {
1228 IOService * driver;
1229 IOPMinformee * informee;
1230 IOPMinformeeList * list = fInterestedDrivers;
1231
1232 PM_LOCK();
1233
1234 if (fInsertInterestSet)
1235 {
1236 while ((driver = (IOService *) fInsertInterestSet->getAnyObject()))
1237 {
1238 if ((list->findItem(driver) == NULL) &&
1239 (!fRemoveInterestSet ||
1240 !fRemoveInterestSet->containsObject(driver)))
1241 {
1242 informee = list->appendNewInformee(driver);
1243 }
1244 fInsertInterestSet->removeObject(driver);
1245 }
1246 fInsertInterestSet->release();
1247 fInsertInterestSet = 0;
1248 }
1249
1250 if (fRemoveInterestSet)
1251 {
1252 while ((driver = (IOService *) fRemoveInterestSet->getAnyObject()))
1253 {
1254 informee = list->findItem(driver);
1255 if (informee)
1256 {
1257 if (fHeadNotePendingAcks && informee->timer)
1258 {
1259 informee->timer = 0;
1260 fHeadNotePendingAcks--;
1261 }
1262 list->removeFromList(driver);
1263 }
1264 fRemoveInterestSet->removeObject(driver);
1265 }
1266 fRemoveInterestSet->release();
1267 fRemoveInterestSet = 0;
1268 }
1269
1270 PM_UNLOCK();
1271 }
1272
1273 //*********************************************************************************
1274 // [public virtual] acknowledgePowerChange
1275 //
1276 // After we notified one of the interested drivers or a power-domain child
1277 // of an impending change in power, it has called to say it is now
1278 // prepared for the change. If this object is the last to
1279 // acknowledge this change, we take whatever action we have been waiting
1280 // for.
1281 // That may include acknowledging to our parent. In this case, we do it
1282 // last of all to insure that this doesn't cause the parent to call us some-
1283 // where else and alter data we are relying on here (like the very existance
1284 // of a "current change note".)
1285 //*********************************************************************************
1286
1287 IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
1288 {
1289 IOPMRequest * request;
1290
1291 if (!initialized)
1292 return IOPMNotYetInitialized;
1293 if (!whichObject)
1294 return kIOReturnBadArgument;
1295
1296 request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1297 if (!request)
1298 {
1299 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
1300 return kIOReturnNoMemory;
1301 }
1302
1303 whichObject->retain();
1304 request->fArg0 = whichObject;
1305
1306 submitPMRequest( request );
1307 return IOPMNoErr;
1308 }
1309
1310 //*********************************************************************************
1311 // [private] handleAcknowledgePowerChange
1312 //*********************************************************************************
1313
1314 bool IOService::handleAcknowledgePowerChange ( IOPMRequest * request )
1315 {
1316 IOPMinformee * informee;
1317 unsigned long childPower = kIOPMUnknown;
1318 IOService * theChild;
1319 IOService * whichObject;
1320 bool all_acked = false;
1321
1322 PM_ASSERT_IN_GATE();
1323 whichObject = (IOService *) request->fArg0;
1324 assert(whichObject);
1325
1326 // one of our interested drivers?
1327 informee = fInterestedDrivers->findItem( whichObject );
1328 if ( informee == NULL )
1329 {
1330 if ( !isChild(whichObject, gIOPowerPlane) )
1331 {
1332 OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1333 goto no_err;
1334 } else {
1335 OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
1336 }
1337 } else {
1338 OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
1339 }
1340
1341 if ( fHeadNotePendingAcks != 0 )
1342 {
1343 assert(fPowerStates != NULL);
1344
1345 // yes, make sure we're expecting acks
1346 if ( informee != NULL )
1347 {
1348 // it's an interested driver
1349 // make sure we're expecting this ack
1350 if ( informee->timer != 0 )
1351 {
1352 #if LOG_SETPOWER_TIMES
1353 if (informee->timer > 0)
1354 {
1355 uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1356 if (nsec > LOG_SETPOWER_TIMES)
1357 PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
1358 informee->whatObject->getName(),
1359 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
1360 informee->whatObject,
1361 fName, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
1362 }
1363 #endif
1364 // mark it acked
1365 informee->timer = 0;
1366 // that's one fewer to worry about
1367 fHeadNotePendingAcks--;
1368 } else {
1369 // this driver has already acked
1370 OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
1371 }
1372 } else {
1373 // it's a child
1374 // make sure we're expecting this ack
1375 if ( ((IOPowerConnection *)whichObject)->getAwaitingAck() )
1376 {
1377 // that's one fewer to worry about
1378 fHeadNotePendingAcks--;
1379 ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1380 theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
1381 if ( theChild )
1382 {
1383 childPower = theChild->currentPowerConsumption();
1384 theChild->release();
1385 }
1386 if ( childPower == kIOPMUnknown )
1387 {
1388 fPowerStates[fHeadNoteState].staticPower = kIOPMUnknown;
1389 } else {
1390 if ( fPowerStates[fHeadNoteState].staticPower != kIOPMUnknown )
1391 {
1392 fPowerStates[fHeadNoteState].staticPower += childPower;
1393 }
1394 }
1395 }
1396 }
1397
1398 if ( fHeadNotePendingAcks == 0 ) {
1399 // yes, stop the timer
1400 stop_ack_timer();
1401 // and now we can continue
1402 all_acked = true;
1403 }
1404 } else {
1405 OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1406 }
1407
1408 no_err:
1409 if (whichObject)
1410 whichObject->release();
1411
1412 return all_acked;
1413 }
1414
1415 //*********************************************************************************
1416 // [public virtual] acknowledgeSetPowerState
1417 //
1418 // After we instructed our controlling driver to change power states,
1419 // it has called to say it has finished doing so.
1420 // We continue to process the power state change.
1421 //*********************************************************************************
1422
1423 IOReturn IOService::acknowledgeSetPowerState ( void )
1424 {
1425 IOPMRequest * request;
1426
1427 if (!initialized)
1428 return IOPMNotYetInitialized;
1429
1430 request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1431 if (!request)
1432 {
1433 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
1434 return kIOReturnNoMemory;
1435 }
1436
1437 submitPMRequest( request );
1438 return kIOReturnSuccess;
1439 }
1440
1441 //*********************************************************************************
1442 // [private] adjustPowerState
1443 //
1444 // Child has signaled a change - child changed it's desire, new child added,
1445 // existing child removed. Adjust our power state accordingly.
1446 //*********************************************************************************
1447
1448 void IOService::adjustPowerState( void )
1449 {
1450 PM_ASSERT_IN_GATE();
1451 if (inPlane(gIOPowerPlane))
1452 {
1453 rebuildChildClampBits();
1454 computeDesiredState();
1455 if ( fControllingDriver && fParentsKnowState )
1456 changeState();
1457 }
1458 else
1459 {
1460 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__);
1461 return;
1462 }
1463 fWillAdjustPowerState = false;
1464 }
1465
1466 //*********************************************************************************
1467 // [public deprecated] powerDomainWillChangeTo
1468 //
1469 // Called by the power-hierarchy parent notifying of a new power state
1470 // in the power domain.
1471 // We enqueue a parent power-change to our queue of power changes.
1472 // This may or may not cause us to change power, depending on what
1473 // kind of change is occuring in the domain.
1474 //*********************************************************************************
1475
1476 IOReturn IOService::powerDomainWillChangeTo (
1477 IOPMPowerFlags newPowerFlags,
1478 IOPowerConnection * whichParent )
1479 {
1480 assert(false);
1481 return kIOReturnUnsupported;
1482 }
1483
1484 //*********************************************************************************
1485 // [private] handlePowerDomainWillChangeTo
1486 //*********************************************************************************
1487
1488 void IOService::handlePowerDomainWillChangeTo ( IOPMRequest * request )
1489 {
1490 IOPMPowerFlags newPowerFlags = (IOPMPowerFlags) request->fArg0;
1491 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1492 bool powerWillDrop = (bool) request->fArg2;
1493 OSIterator * iter;
1494 OSObject * next;
1495 IOPowerConnection * connection;
1496 unsigned long newPowerState;
1497 IOPMPowerFlags combinedPowerFlags;
1498 bool savedParentsKnowState;
1499 IOReturn result = IOPMAckImplied;
1500
1501 PM_ASSERT_IN_GATE();
1502 OUR_PMLog(kPMLogWillChange, newPowerFlags, 0);
1503
1504 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
1505 {
1506 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__);
1507 goto exit_no_ack;
1508 }
1509
1510 savedParentsKnowState = fParentsKnowState;
1511
1512 // Combine parents' power flags to determine our maximum state
1513 // within the new power domain
1514 combinedPowerFlags = 0;
1515
1516 iter = getParentIterator(gIOPowerPlane);
1517 if ( iter )
1518 {
1519 while ( (next = iter->getNextObject()) )
1520 {
1521 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
1522 {
1523 if ( connection == whichParent )
1524 combinedPowerFlags |= newPowerFlags;
1525 else
1526 combinedPowerFlags |= connection->parentCurrentPowerFlags();
1527 }
1528 }
1529 iter->release();
1530 }
1531
1532 if ( fControllingDriver )
1533 {
1534 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1535 combinedPowerFlags);
1536
1537 result = enqueuePowerChange(
1538 /* flags */ IOPMParentInitiated | IOPMDomainWillChange,
1539 /* power state */ newPowerState,
1540 /* domain state */ combinedPowerFlags,
1541 /* connection */ whichParent,
1542 /* parent state */ newPowerFlags);
1543 }
1544
1545 // If parent is dropping power, immediately update the parent's
1546 // capability flags. Any future merging of parent(s) combined
1547 // power flags should account for this power drop.
1548
1549 if (powerWillDrop)
1550 {
1551 setParentInfo(newPowerFlags, whichParent, true);
1552 }
1553
1554 // Parent is expecting an ACK from us. If we did not embark on a state
1555 // transition, when enqueuePowerChang() returns IOPMAckImplied. We are
1556 // still required to issue an ACK to our parent.
1557
1558 if (IOPMAckImplied == result)
1559 {
1560 IOService * parent;
1561 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1562 assert(parent);
1563 if ( parent )
1564 {
1565 parent->acknowledgePowerChange( whichParent );
1566 parent->release();
1567 }
1568 }
1569
1570 // If the parent registers it's power driver late, then this is the
1571 // first opportunity to tell our parent about our desire.
1572
1573 if (!savedParentsKnowState && fParentsKnowState)
1574 {
1575 PM_TRACE("[%s] powerDomainWillChangeTo: parentsKnowState = true\n",
1576 getName());
1577 ask_parent( fDesiredPowerState );
1578 }
1579
1580 exit_no_ack:
1581 // Drop the retain from notifyChild().
1582 if (whichParent) whichParent->release();
1583 }
1584
1585 //*********************************************************************************
1586 // [public deprecated] powerDomainDidChangeTo
1587 //
1588 // Called by the power-hierarchy parent after the power state of the power domain
1589 // has settled at a new level.
1590 // We enqueue a parent power-change to our queue of power changes.
1591 // This may or may not cause us to change power, depending on what
1592 // kind of change is occuring in the domain.
1593 //*********************************************************************************
1594
1595 IOReturn IOService::powerDomainDidChangeTo (
1596 IOPMPowerFlags newPowerFlags,
1597 IOPowerConnection * whichParent )
1598 {
1599 assert(false);
1600 return kIOReturnUnsupported;
1601 }
1602
1603 //*********************************************************************************
1604 // [private] handlePowerDomainDidChangeTo
1605 //*********************************************************************************
1606
1607 void IOService::handlePowerDomainDidChangeTo ( IOPMRequest * request )
1608 {
1609 IOPMPowerFlags newPowerFlags = (IOPMPowerFlags) request->fArg0;
1610 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1611 unsigned long newPowerState;
1612 bool savedParentsKnowState;
1613 IOReturn result = IOPMAckImplied;
1614
1615 PM_ASSERT_IN_GATE();
1616 OUR_PMLog(kPMLogDidChange, newPowerFlags, 0);
1617
1618 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
1619 {
1620 PM_DEBUG("[%s] %s: not in power tree\n", getName(), __FUNCTION__);
1621 goto exit_no_ack;
1622 }
1623
1624 savedParentsKnowState = fParentsKnowState;
1625
1626 setParentInfo(newPowerFlags, whichParent, true);
1627
1628 if ( fControllingDriver )
1629 {
1630 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1631 fParentsCurrentPowerFlags);
1632
1633 result = enqueuePowerChange(
1634 /* flags */ IOPMParentInitiated | IOPMDomainDidChange,
1635 /* power state */ newPowerState,
1636 /* domain state */ fParentsCurrentPowerFlags,
1637 /* connection */ whichParent,
1638 /* parent state */ 0);
1639 }
1640
1641 // Parent is expecting an ACK from us. If we did not embark on a state
1642 // transition, when enqueuePowerChang() returns IOPMAckImplied. We are
1643 // still required to issue an ACK to our parent.
1644
1645 if (IOPMAckImplied == result)
1646 {
1647 IOService * parent;
1648 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1649 assert(parent);
1650 if ( parent )
1651 {
1652 parent->acknowledgePowerChange( whichParent );
1653 parent->release();
1654 }
1655 }
1656
1657 // If the parent registers it's power driver late, then this is the
1658 // first opportunity to tell our parent about our desire.
1659
1660 if (!savedParentsKnowState && fParentsKnowState)
1661 {
1662 PM_TRACE("[%s] powerDomainDidChangeTo: parentsKnowState = true\n",
1663 getName());
1664 ask_parent( fDesiredPowerState );
1665 }
1666
1667 exit_no_ack:
1668 // Drop the retain from notifyChild().
1669 if (whichParent) whichParent->release();
1670 }
1671
1672 //*********************************************************************************
1673 // [private] setParentInfo
1674 //
1675 // Set our connection data for one specific parent, and then combine all the parent
1676 // data together.
1677 //*********************************************************************************
1678
1679 void IOService::setParentInfo (
1680 IOPMPowerFlags newPowerFlags,
1681 IOPowerConnection * whichParent,
1682 bool knowsState )
1683 {
1684 OSIterator * iter;
1685 OSObject * next;
1686 IOPowerConnection * conn;
1687
1688 PM_ASSERT_IN_GATE();
1689
1690 // set our connection data
1691 whichParent->setParentCurrentPowerFlags(newPowerFlags);
1692 whichParent->setParentKnowsState(knowsState);
1693
1694 // recompute our parent info
1695 fParentsCurrentPowerFlags = 0;
1696 fParentsKnowState = true;
1697
1698 iter = getParentIterator(gIOPowerPlane);
1699 if ( iter )
1700 {
1701 while ( (next = iter->getNextObject()) )
1702 {
1703 if ( (conn = OSDynamicCast(IOPowerConnection, next)) )
1704 {
1705 fParentsKnowState &= conn->parentKnowsState();
1706 fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
1707 }
1708 }
1709 iter->release();
1710 }
1711 }
1712
1713 //*********************************************************************************
1714 // [private] rebuildChildClampBits
1715 //
1716 // The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1717 // indicate that one of our children (or grandchildren or great-grandchildren ...)
1718 // doesn't support idle or system sleep in its current state. Since we don't track
1719 // the origin of each bit, every time any child changes state we have to clear
1720 // these bits and rebuild them.
1721 //*********************************************************************************
1722
1723 void IOService::rebuildChildClampBits ( void )
1724 {
1725 unsigned long i;
1726 OSIterator * iter;
1727 OSObject * next;
1728 IOPowerConnection * connection;
1729 unsigned long powerState;
1730
1731 // A child's desires has changed. We need to rebuild the child-clamp bits in
1732 // our power state array. Start by clearing the bits in each power state.
1733
1734 for ( i = 0; i < fNumberOfPowerStates; i++ )
1735 {
1736 fPowerStates[i].capabilityFlags &= ~(kIOPMChildClamp | kIOPMChildClamp2);
1737 }
1738
1739 // Loop through the children. When we encounter the calling child, save the
1740 // computed state as this child's desire. And set the ChildClamp bits in any
1741 // of our states that some child has clamp on.
1742
1743 iter = getChildIterator(gIOPowerPlane);
1744 if ( iter )
1745 {
1746 while ( (next = iter->getNextObject()) )
1747 {
1748 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
1749 {
1750 if (connection->getReadyFlag() == false)
1751 {
1752 PM_CONNECT("[%s] %s: connection not ready\n",
1753 getName(), __FUNCTION__);
1754 continue;
1755 }
1756
1757 powerState = connection->getDesiredDomainState();
1758 if (powerState < fNumberOfPowerStates)
1759 {
1760 if ( connection->getPreventIdleSleepFlag() )
1761 fPowerStates[powerState].capabilityFlags |= kIOPMChildClamp;
1762 if ( connection->getPreventSystemSleepFlag() )
1763 fPowerStates[powerState].capabilityFlags |= kIOPMChildClamp2;
1764 }
1765 }
1766 }
1767 iter->release();
1768 }
1769 }
1770
1771 //*********************************************************************************
1772 // [public virtual] requestPowerDomainState
1773 //
1774 // The child of a power domain calls it parent here to request power of a certain
1775 // character.
1776 //*********************************************************************************
1777
1778 IOReturn IOService::requestPowerDomainState (
1779 IOPMPowerFlags desiredState,
1780 IOPowerConnection * whichChild,
1781 unsigned long specification )
1782 {
1783 unsigned long i;
1784 unsigned long computedState;
1785 unsigned long theDesiredState;
1786 IOService * child;
1787
1788 if (!initialized)
1789 return IOPMNotYetInitialized;
1790
1791 if (gIOPMWorkLoop->onThread() == false)
1792 {
1793 PM_DEBUG("[%s] called requestPowerDomainState\n", getName());
1794 return kIOReturnSuccess;
1795 }
1796
1797 theDesiredState = desiredState & ~(kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
1798
1799 OUR_PMLog(kPMLogRequestDomain, desiredState, specification);
1800
1801 if (!isChild(whichChild, gIOPowerPlane))
1802 return kIOReturnNotAttached;
1803
1804 if (fControllingDriver == NULL || !fPowerStates)
1805 return IOPMNotYetInitialized;
1806
1807 child = (IOService *) whichChild->getChildEntry(gIOPowerPlane);
1808 assert(child);
1809
1810 switch (specification) {
1811 case IOPMLowestState:
1812 i = 0;
1813 while ( i < fNumberOfPowerStates )
1814 {
1815 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
1816 (theDesiredState & fOutputPowerCharacterFlags) )
1817 {
1818 break;
1819 }
1820 i++;
1821 }
1822 if ( i >= fNumberOfPowerStates )
1823 {
1824 return IOPMNoSuchState;
1825 }
1826 break;
1827
1828 case IOPMNextLowerState:
1829 i = fCurrentPowerState - 1;
1830 while ( (int) i >= 0 )
1831 {
1832 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
1833 (theDesiredState & fOutputPowerCharacterFlags) )
1834 {
1835 break;
1836 }
1837 i--;
1838 }
1839 if ( (int) i < 0 )
1840 {
1841 return IOPMNoSuchState;
1842 }
1843 break;
1844
1845 case IOPMHighestState:
1846 i = fNumberOfPowerStates;
1847 while ( (int) i >= 0 )
1848 {
1849 i--;
1850 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
1851 (theDesiredState & fOutputPowerCharacterFlags) )
1852 {
1853 break;
1854 }
1855 }
1856 if ( (int) i < 0 )
1857 {
1858 return IOPMNoSuchState;
1859 }
1860 break;
1861
1862 case IOPMNextHigherState:
1863 i = fCurrentPowerState + 1;
1864 while ( i < fNumberOfPowerStates )
1865 {
1866 if ( ( fPowerStates[i].outputPowerCharacter & theDesiredState) ==
1867 (theDesiredState & fOutputPowerCharacterFlags) )
1868 {
1869 break;
1870 }
1871 i++;
1872 }
1873 if ( i == fNumberOfPowerStates )
1874 {
1875 return IOPMNoSuchState;
1876 }
1877 break;
1878
1879 default:
1880 return IOPMBadSpecification;
1881 }
1882
1883 computedState = i;
1884
1885 // Clamp removed on the initial power request from a new child.
1886
1887 if (fClampOn && !whichChild->childHasRequestedPower())
1888 {
1889 PM_TRACE("[%s] %p power clamp removed (child = %p)\n",
1890 getName(), this, whichChild);
1891 fClampOn = false;
1892 fDeviceDesire = 0;
1893 }
1894
1895 // Record the child's desires on the connection.
1896
1897 whichChild->setDesiredDomainState( computedState );
1898 whichChild->setPreventIdleSleepFlag( desiredState & kIOPMPreventIdleSleep );
1899 whichChild->setPreventSystemSleepFlag( desiredState & kIOPMPreventSystemSleep );
1900 whichChild->setChildHasRequestedPower();
1901
1902 if (whichChild->getReadyFlag() == false)
1903 return IOPMNoErr;
1904
1905 // Issue a ping for us to re-evaluate all children desires and
1906 // possibly change power state.
1907
1908 if (!fWillAdjustPowerState && !fDeviceOverrides)
1909 {
1910 IOPMRequest * childRequest;
1911
1912 childRequest = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1913 if (childRequest)
1914 {
1915 submitPMRequest( childRequest );
1916 fWillAdjustPowerState = true;
1917 }
1918 }
1919
1920 return IOPMNoErr;
1921 }
1922
1923 //*********************************************************************************
1924 // [public virtual] temporaryPowerClampOn
1925 //
1926 // A power domain wants to clamp its power on till it has children which
1927 // will thendetermine the power domain state.
1928 //
1929 // We enter the highest state until addPowerChild is called.
1930 //*********************************************************************************
1931
1932 IOReturn IOService::temporaryPowerClampOn ( void )
1933 {
1934 IOPMRequest * request;
1935
1936 if (!initialized)
1937 return IOPMNotYetInitialized;
1938
1939 request = acquirePMRequest( this, kIOPMRequestTypeTemporaryPowerClamp );
1940 if (!request)
1941 return kIOReturnNoMemory;
1942
1943 submitPMRequest( request );
1944 return IOPMNoErr;
1945 }
1946
1947 //*********************************************************************************
1948 // [public virtual] makeUsable
1949 //
1950 // Some client of our device is asking that we become usable. Although
1951 // this has not come from a subclassed device object, treat it exactly
1952 // as if it had. In this way, subsequent requests for lower power from
1953 // a subclassed device object will pre-empt this request.
1954 //
1955 // We treat this as a subclass object request to switch to the
1956 // highest power state.
1957 //*********************************************************************************
1958
1959 IOReturn IOService::makeUsable ( void )
1960 {
1961 IOPMRequest * request;
1962
1963 if (!initialized)
1964 return IOPMNotYetInitialized;
1965
1966 OUR_PMLog(kPMLogMakeUsable, 0, 0);
1967
1968 request = acquirePMRequest( this, kIOPMRequestTypeMakeUsable );
1969 if (!request)
1970 return kIOReturnNoMemory;
1971
1972 submitPMRequest( request );
1973 return IOPMNoErr;
1974 }
1975
1976 //*********************************************************************************
1977 // [private] handleMakeUsable
1978 //
1979 // Handle a request to become usable.
1980 //*********************************************************************************
1981
1982 void IOService::handleMakeUsable ( IOPMRequest * request )
1983 {
1984 PM_ASSERT_IN_GATE();
1985 if ( fControllingDriver )
1986 {
1987 fDeviceDesire = fNumberOfPowerStates - 1;
1988 computeDesiredState();
1989 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
1990 {
1991 changeState();
1992 }
1993 }
1994 else
1995 {
1996 fNeedToBecomeUsable = true;
1997 }
1998 }
1999
2000 //*********************************************************************************
2001 // [public virtual] currentCapability
2002 //*********************************************************************************
2003
2004 IOPMPowerFlags IOService::currentCapability ( void )
2005 {
2006 if (!initialized)
2007 return IOPMNotPowerManaged;
2008
2009 return fCurrentCapabilityFlags;
2010 }
2011
2012 //*********************************************************************************
2013 // [public virtual] changePowerStateTo
2014 //
2015 // For some reason, our power-controlling driver has decided it needs to change
2016 // power state. We enqueue the power change so that appropriate parties
2017 // will be notified, and then we will instruct the driver to make the change.
2018 //*********************************************************************************
2019
2020 IOReturn IOService::changePowerStateTo ( unsigned long ordinal )
2021 {
2022 IOPMRequest * request;
2023
2024 if (!initialized)
2025 return IOPMNotYetInitialized;
2026
2027 OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2028
2029 request = acquirePMRequest( this, kIOPMRequestTypeChangePowerStateTo );
2030 if (!request)
2031 return kIOReturnNoMemory;
2032
2033 request->fArg0 = (void *) ordinal;
2034 request->fArg1 = (void *) false;
2035
2036 // Avoid needless downwards power transitions by clamping power in
2037 // computeDesiredState() until the delayed request is processed.
2038
2039 if (gIOPMWorkLoop->inGate())
2040 {
2041 fTempClampPowerState = max(fTempClampPowerState, ordinal);
2042 fTempClampCount++;
2043 request->fArg1 = (void *) true;
2044 }
2045
2046 submitPMRequest( request );
2047 return IOPMNoErr;
2048 }
2049
2050 //*********************************************************************************
2051 // [private] handleChangePowerStateTo
2052 //*********************************************************************************
2053
2054 void IOService::handleChangePowerStateTo ( IOPMRequest * request )
2055 {
2056 unsigned long ordinal = (unsigned long) request->fArg0;
2057
2058 PM_ASSERT_IN_GATE();
2059 if (request->fArg1)
2060 {
2061 assert(fTempClampCount != 0);
2062 if (fTempClampCount)
2063 fTempClampCount--;
2064 if (!fTempClampCount)
2065 fTempClampPowerState = 0;
2066 }
2067
2068 if ( fControllingDriver && (ordinal < fNumberOfPowerStates))
2069 {
2070 fDriverDesire = ordinal;
2071 computeDesiredState();
2072 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
2073 {
2074 changeState();
2075 }
2076 }
2077 }
2078
2079 //*********************************************************************************
2080 // [public virtual] changePowerStateToPriv
2081 //
2082 // For some reason, a subclassed device object has decided it needs to change
2083 // power state. We enqueue the power change so that appropriate parties
2084 // will be notified, and then we will instruct the driver to make the change.
2085 //*********************************************************************************
2086
2087 IOReturn IOService::changePowerStateToPriv ( unsigned long ordinal )
2088 {
2089 IOPMRequest * request;
2090
2091 if (!initialized)
2092 return IOPMNotYetInitialized;
2093
2094 request = acquirePMRequest( this, kIOPMRequestTypeChangePowerStateToPriv );
2095 if (!request)
2096 return kIOReturnNoMemory;
2097
2098 request->fArg0 = (void *) ordinal;
2099 request->fArg1 = (void *) false;
2100
2101 // Avoid needless downwards power transitions by clamping power in
2102 // computeDesiredState() until the delayed request is processed.
2103
2104 if (gIOPMWorkLoop->inGate())
2105 {
2106 fTempClampPowerState = max(fTempClampPowerState, ordinal);
2107 fTempClampCount++;
2108 request->fArg1 = (void *) true;
2109 }
2110
2111 submitPMRequest( request );
2112 return IOPMNoErr;
2113 }
2114
2115 //*********************************************************************************
2116 // [private] handleChangePowerStateToPriv
2117 //*********************************************************************************
2118
2119 void IOService::handleChangePowerStateToPriv ( IOPMRequest * request )
2120 {
2121 unsigned long ordinal = (unsigned long) request->fArg0;
2122
2123 PM_ASSERT_IN_GATE();
2124 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2125 if (request->fArg1)
2126 {
2127 assert(fTempClampCount != 0);
2128 if (fTempClampCount)
2129 fTempClampCount--;
2130 if (!fTempClampCount)
2131 fTempClampPowerState = 0;
2132 }
2133
2134 if ( fControllingDriver && (ordinal < fNumberOfPowerStates))
2135 {
2136 fDeviceDesire = ordinal;
2137 computeDesiredState();
2138 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
2139 {
2140 changeState();
2141 }
2142 }
2143 }
2144
2145 //*********************************************************************************
2146 // [private] computeDesiredState
2147 //*********************************************************************************
2148
2149 void IOService::computeDesiredState ( unsigned long tempDesire )
2150 {
2151 OSIterator * iter;
2152 OSObject * next;
2153 IOPowerConnection * connection;
2154 unsigned long newDesiredState = 0;
2155 unsigned long childDesire = 0;
2156 unsigned long deviceDesire;
2157
2158 if (tempDesire)
2159 deviceDesire = tempDesire;
2160 else
2161 deviceDesire = fDeviceDesire;
2162
2163 // If clamp is on, always override deviceDesire to max.
2164
2165 if (fClampOn && fNumberOfPowerStates)
2166 deviceDesire = fNumberOfPowerStates - 1;
2167
2168 // Compute the maximum of our children's desires,
2169 // our controlling driver's desire, and the subclass device's desire.
2170
2171 if ( !fDeviceOverrides )
2172 {
2173 iter = getChildIterator(gIOPowerPlane);
2174 if ( iter )
2175 {
2176 while ( (next = iter->getNextObject()) )
2177 {
2178 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
2179 {
2180 if (connection->getReadyFlag() == false)
2181 {
2182 PM_CONNECT("[%s] %s: connection not ready\n",
2183 getName(), __FUNCTION__);
2184 continue;
2185 }
2186
2187 if (connection->getDesiredDomainState() > childDesire)
2188 childDesire = connection->getDesiredDomainState();
2189 }
2190 }
2191 iter->release();
2192 }
2193
2194 fChildrenDesire = childDesire;
2195 newDesiredState = max(childDesire, fDriverDesire);
2196 }
2197
2198 newDesiredState = max(deviceDesire, newDesiredState);
2199 if (fTempClampCount && (fTempClampPowerState < fNumberOfPowerStates))
2200 newDesiredState = max(fTempClampPowerState, newDesiredState);
2201
2202 fDesiredPowerState = newDesiredState;
2203
2204 // Limit check against number of power states.
2205
2206 if (fNumberOfPowerStates == 0)
2207 fDesiredPowerState = 0;
2208 else if (fDesiredPowerState >= fNumberOfPowerStates)
2209 fDesiredPowerState = fNumberOfPowerStates - 1;
2210
2211 // Restart idle timer if stopped and deviceDesire has increased.
2212
2213 if (fDeviceDesire && fActivityTimerStopped)
2214 {
2215 fActivityTimerStopped = false;
2216 start_PM_idle_timer();
2217 }
2218
2219 // Invalidate cached tickle power state when desires change, and not
2220 // due to a tickle request. This invalidation must occur before the
2221 // power state change to minimize races. We want to err on the side
2222 // of servicing more activity tickles rather than dropping one when
2223 // the device is in a low power state.
2224
2225 if (fPMRequest && (fPMRequest->getType() != kIOPMRequestTypeActivityTickle) &&
2226 (fActivityTicklePowerState != -1))
2227 {
2228 IOLockLock(fActivityLock);
2229 fActivityTicklePowerState = -1;
2230 IOLockUnlock(fActivityLock);
2231 }
2232
2233 PM_TRACE(" NewState %ld, Child %ld, Driver %ld, Device %ld, Clamp %d (%ld)\n",
2234 fDesiredPowerState, childDesire, fDriverDesire, deviceDesire,
2235 fClampOn, fTempClampCount ? fTempClampPowerState : 0);
2236 }
2237
2238 //*********************************************************************************
2239 // [private] changeState
2240 //
2241 // A subclass object, our controlling driver, or a power domain child
2242 // has asked for a different power state. Here we compute what new
2243 // state we should enter and enqueue the change (or start it).
2244 //*********************************************************************************
2245
2246 IOReturn IOService::changeState ( void )
2247 {
2248 IOReturn result;
2249
2250 PM_ASSERT_IN_GATE();
2251 assert(inPlane(gIOPowerPlane));
2252 assert(fParentsKnowState);
2253 assert(fControllingDriver);
2254
2255 result = enqueuePowerChange(
2256 /* flags */ IOPMWeInitiated,
2257 /* power state */ fDesiredPowerState,
2258 /* domain state */ 0,
2259 /* connection */ 0,
2260 /* parent state */ 0);
2261
2262 return result;
2263 }
2264
2265 //*********************************************************************************
2266 // [public virtual] currentPowerConsumption
2267 //
2268 //*********************************************************************************
2269
2270 unsigned long IOService::currentPowerConsumption ( void )
2271 {
2272 if (!initialized)
2273 return kIOPMUnknown;
2274
2275 return fCurrentPowerConsumption;
2276 }
2277
2278 //*********************************************************************************
2279 // [public virtual] getPMworkloop
2280 //*********************************************************************************
2281
2282 IOWorkLoop * IOService::getPMworkloop ( void )
2283 {
2284 return gIOPMWorkLoop;
2285 }
2286
2287 //*********************************************************************************
2288 // [public virtual] activityTickle
2289 //
2290 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
2291 // flag to be set, and the device state checked. If the device has been
2292 // powered down, it is powered up again.
2293 // The tickle with parameter kIOPMSubclassPolicy is ignored here and
2294 // should be intercepted by a subclass.
2295 //*********************************************************************************
2296
2297 bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber )
2298 {
2299 IOPMRequest * request;
2300 bool noPowerChange = true;
2301
2302 if ( initialized && stateNumber && (type == kIOPMSuperclassPolicy1) )
2303 {
2304 IOLockLock(fActivityLock);
2305
2306 // Record device activity for the idle timer handler.
2307
2308 fDeviceActive = true;
2309 clock_get_uptime(&fDeviceActiveTimestamp);
2310
2311 // Record the last tickle power state.
2312 // This helps to filter out redundant tickles as
2313 // this function may be called from the data path.
2314
2315 if (fActivityTicklePowerState < (long)stateNumber)
2316 {
2317 fActivityTicklePowerState = stateNumber;
2318 noPowerChange = false;
2319
2320 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2321 if (request)
2322 {
2323 request->fArg0 = (void *) stateNumber; // power state
2324 request->fArg1 = (void *) true; // power rise
2325 submitPMRequest(request);
2326 }
2327 }
2328
2329 IOLockUnlock(fActivityLock);
2330 }
2331
2332 // Returns false if the activityTickle might cause a transition to a
2333 // higher powered state, true otherwise.
2334
2335 return noPowerChange;
2336 }
2337
2338 //*********************************************************************************
2339 // [public virtual] setIdleTimerPeriod
2340 //
2341 // A subclass policy-maker is going to use our standard idleness
2342 // detection service. Make a command queue and an idle timer and
2343 // connect them to the power management workloop. Finally,
2344 // start the timer.
2345 //*********************************************************************************
2346
2347 IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
2348 {
2349 IOWorkLoop * wl = getPMworkloop();
2350
2351 if (!initialized || !wl)
2352 return IOPMNotYetInitialized;
2353
2354 OUR_PMLog(PMsetIdleTimerPeriod, period, 0);
2355
2356 fIdleTimerPeriod = period;
2357
2358 if ( period > 0 )
2359 {
2360 // make the timer event
2361 if ( fIdleTimerEventSource == NULL )
2362 {
2363 IOTimerEventSource * timerSrc;
2364
2365 timerSrc = IOTimerEventSource::timerEventSource(
2366 this, PM_idle_timer_expired);
2367
2368 if (timerSrc && (wl->addEventSource(timerSrc) != kIOReturnSuccess))
2369 {
2370 timerSrc->release();
2371 timerSrc = 0;
2372 }
2373
2374 fIdleTimerEventSource = timerSrc;
2375 }
2376
2377 start_PM_idle_timer();
2378 }
2379 return IOPMNoErr;
2380 }
2381
2382 //******************************************************************************
2383 // [public virtual] nextIdleTimeout
2384 //
2385 // Returns how many "seconds from now" the device should idle into its
2386 // next lowest power state.
2387 //******************************************************************************
2388
2389 SInt32 IOService::nextIdleTimeout(
2390 AbsoluteTime currentTime,
2391 AbsoluteTime lastActivity,
2392 unsigned int powerState)
2393 {
2394 AbsoluteTime delta;
2395 UInt64 delta_ns;
2396 SInt32 delta_secs;
2397 SInt32 delay_secs;
2398
2399 // Calculate time difference using funky macro from clock.h.
2400 delta = currentTime;
2401 SUB_ABSOLUTETIME(&delta, &lastActivity);
2402
2403 // Figure it in seconds.
2404 absolutetime_to_nanoseconds(delta, &delta_ns);
2405 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
2406
2407 // Be paranoid about delta somehow exceeding timer period.
2408 if (delta_secs < (int) fIdleTimerPeriod )
2409 delay_secs = (int) fIdleTimerPeriod - delta_secs;
2410 else
2411 delay_secs = (int) fIdleTimerPeriod;
2412
2413 return (SInt32)delay_secs;
2414 }
2415
2416 //******************************************************************************
2417 // [public virtual] start_PM_idle_timer
2418 //
2419 // The parameter is a pointer to us. Use it to call our timeout method.
2420 //******************************************************************************
2421
2422 void IOService::start_PM_idle_timer ( void )
2423 {
2424 static const int maxTimeout = 100000;
2425 static const int minTimeout = 1;
2426 AbsoluteTime uptime;
2427 SInt32 idle_in = 0;
2428
2429 if (!initialized || !fIdleTimerEventSource)
2430 return;
2431
2432 IOLockLock(fActivityLock);
2433
2434 clock_get_uptime(&uptime);
2435
2436 // Subclasses may modify idle sleep algorithm
2437 idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, fCurrentPowerState);
2438
2439 // Check for out-of range responses
2440 if (idle_in > maxTimeout)
2441 {
2442 // use standard implementation
2443 idle_in = IOService::nextIdleTimeout(uptime,
2444 fDeviceActiveTimestamp,
2445 fCurrentPowerState);
2446 } else if (idle_in < minTimeout) {
2447 idle_in = fIdleTimerPeriod;
2448 }
2449
2450 IOLockUnlock(fActivityLock);
2451
2452 fIdleTimerEventSource->setTimeout(idle_in, NSEC_PER_SEC);
2453 }
2454
2455 //*********************************************************************************
2456 // [private] PM_idle_timer_expired
2457 //
2458 // The parameter is a pointer to us. Use it to call our timeout method.
2459 //*********************************************************************************
2460
2461 void PM_idle_timer_expired ( OSObject * ourSelves, IOTimerEventSource * )
2462 {
2463 ((IOService *)ourSelves)->PM_idle_timer_expiration();
2464 }
2465
2466 //*********************************************************************************
2467 // [public virtual] PM_idle_timer_expiration
2468 //
2469 // The idle timer has expired. If there has been activity since the last
2470 // expiration, just restart the timer and return. If there has not been
2471 // activity, switch to the next lower power state and restart the timer.
2472 //*********************************************************************************
2473
2474 void IOService::PM_idle_timer_expiration ( void )
2475 {
2476 IOPMRequest * request;
2477 bool restartTimer = true;
2478
2479 if ( !initialized || !fIdleTimerPeriod )
2480 return;
2481
2482 IOLockLock(fActivityLock);
2483
2484 // Check for device activity (tickles) over last timer period.
2485
2486 if (fDeviceActive)
2487 {
2488 // Device was active - do not drop power, restart timer.
2489 fDeviceActive = false;
2490 }
2491 else
2492 {
2493 // No device activity - drop power state by one level.
2494 // Decrement the cached tickle power state when possible.
2495 // This value may be (-1) before activityTickle() is called,
2496 // but the power drop request must be issued regardless.
2497
2498 if (fActivityTicklePowerState > 0)
2499 {
2500 fActivityTicklePowerState--;
2501 }
2502
2503 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2504 if (request)
2505 {
2506 request->fArg0 = (void *) 0; // power state (irrelevant)
2507 request->fArg1 = (void *) false; // power drop
2508 submitPMRequest( request );
2509
2510 // Do not restart timer until after the tickle request has been
2511 // processed.
2512
2513 restartTimer = false;
2514 }
2515 }
2516
2517 IOLockUnlock(fActivityLock);
2518
2519 if (restartTimer)
2520 start_PM_idle_timer();
2521 }
2522
2523 //*********************************************************************************
2524 // [public virtual] command_received
2525 //
2526 //*********************************************************************************
2527
2528 void IOService::command_received ( void *statePtr , void *, void * , void * )
2529 {
2530 }
2531
2532 //*********************************************************************************
2533 // [public virtual] setAggressiveness
2534 //
2535 // Pass on the input parameters to all power domain children. All those which are
2536 // power domains will pass it on to their children, etc.
2537 //*********************************************************************************
2538
2539 IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
2540 {
2541 OSIterator * iter;
2542 OSObject * next;
2543 IOPowerConnection * connection;
2544 IOService * child;
2545
2546 if (!initialized)
2547 return IOPMNotYetInitialized;
2548
2549 if (getPMRootDomain() == this)
2550 OUR_PMLog(kPMLogSetAggressiveness, type, newLevel);
2551
2552 if ( type <= kMaxType )
2553 {
2554 fAggressivenessValue[type] = newLevel;
2555 fAggressivenessValid[type] = true;
2556 }
2557
2558 iter = getChildIterator(gIOPowerPlane);
2559 if ( iter )
2560 {
2561 while ( (next = iter->getNextObject()) )
2562 {
2563 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
2564 {
2565 if (connection->getReadyFlag() == false)
2566 {
2567 PM_CONNECT("[%s] %s: connection not ready\n",
2568 getName(), __FUNCTION__);
2569 continue;
2570 }
2571
2572 child = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
2573 if ( child )
2574 {
2575 child->setAggressiveness(type, newLevel);
2576 child->release();
2577 }
2578 }
2579 }
2580 iter->release();
2581 }
2582
2583 return IOPMNoErr;
2584 }
2585
2586 //*********************************************************************************
2587 // [public virtual] getAggressiveness
2588 //
2589 // Called by the user client.
2590 //*********************************************************************************
2591
2592 IOReturn IOService::getAggressiveness ( unsigned long type, unsigned long * currentLevel )
2593 {
2594 if ( !initialized || (type > kMaxType) )
2595 return kIOReturnBadArgument;
2596
2597 if ( !fAggressivenessValid[type] )
2598 return kIOReturnInvalid;
2599
2600 *currentLevel = fAggressivenessValue[type];
2601
2602 return kIOReturnSuccess;
2603 }
2604
2605 //*********************************************************************************
2606 // [public] getPowerState
2607 //
2608 //*********************************************************************************
2609
2610 UInt32 IOService::getPowerState ( void )
2611 {
2612 if (!initialized)
2613 return 0;
2614
2615 return fCurrentPowerState;
2616 }
2617
2618 //*********************************************************************************
2619 // [public virtual] systemWake
2620 //
2621 // Pass this to all power domain children. All those which are
2622 // power domains will pass it on to their children, etc.
2623 //*********************************************************************************
2624
2625 IOReturn IOService::systemWake ( void )
2626 {
2627 OSIterator * iter;
2628 OSObject * next;
2629 IOPowerConnection * connection;
2630 IOService * theChild;
2631
2632 OUR_PMLog(kPMLogSystemWake, 0, 0);
2633
2634 iter = getChildIterator(gIOPowerPlane);
2635 if ( iter )
2636 {
2637 while ( (next = iter->getNextObject()) )
2638 {
2639 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
2640 {
2641 if (connection->getReadyFlag() == false)
2642 {
2643 PM_CONNECT("[%s] %s: connection not ready\n",
2644 getName(), __FUNCTION__);
2645 continue;
2646 }
2647
2648 theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
2649 if ( theChild )
2650 {
2651 theChild->systemWake();
2652 theChild->release();
2653 }
2654 }
2655 }
2656 iter->release();
2657 }
2658
2659 if ( fControllingDriver != NULL )
2660 {
2661 if ( fControllingDriver->didYouWakeSystem() )
2662 {
2663 makeUsable();
2664 }
2665 }
2666
2667 return IOPMNoErr;
2668 }
2669
2670 //*********************************************************************************
2671 // [public virtual] temperatureCriticalForZone
2672 //*********************************************************************************
2673
2674 IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
2675 {
2676 IOService * theParent;
2677 IOService * theNub;
2678
2679 OUR_PMLog(kPMLogCriticalTemp, 0, 0);
2680
2681 if ( inPlane(gIOPowerPlane) && !fWeAreRoot )
2682 {
2683 theNub = (IOService *)copyParentEntry(gIOPowerPlane);
2684 if ( theNub )
2685 {
2686 theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
2687 theNub->release();
2688 if ( theParent )
2689 {
2690 theParent->temperatureCriticalForZone(whichZone);
2691 theParent->release();
2692 }
2693 }
2694 }
2695 return IOPMNoErr;
2696 }
2697
2698 //*********************************************************************************
2699 // [public] powerOverrideOnPriv
2700 //*********************************************************************************
2701
2702 IOReturn IOService::powerOverrideOnPriv ( void )
2703 {
2704 IOPMRequest * request;
2705
2706 if (!initialized)
2707 return IOPMNotYetInitialized;
2708
2709 if (gIOPMWorkLoop->inGate())
2710 {
2711 fDeviceOverrides = true;
2712 return IOPMNoErr;
2713 }
2714
2715 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2716 if (!request)
2717 return kIOReturnNoMemory;
2718
2719 submitPMRequest( request );
2720 return IOPMNoErr;
2721 }
2722
2723 //*********************************************************************************
2724 // [public] powerOverrideOffPriv
2725 //*********************************************************************************
2726
2727 IOReturn IOService::powerOverrideOffPriv ( void )
2728 {
2729 IOPMRequest * request;
2730
2731 if (!initialized)
2732 return IOPMNotYetInitialized;
2733
2734 if (gIOPMWorkLoop->inGate())
2735 {
2736 fDeviceOverrides = false;
2737 return IOPMNoErr;
2738 }
2739
2740 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2741 if (!request)
2742 return kIOReturnNoMemory;
2743
2744 submitPMRequest( request );
2745 return IOPMNoErr;
2746 }
2747
2748 //*********************************************************************************
2749 // [private] handlePowerOverrideChanged
2750 //*********************************************************************************
2751
2752 void IOService::handlePowerOverrideChanged ( IOPMRequest * request )
2753 {
2754 PM_ASSERT_IN_GATE();
2755 if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv)
2756 {
2757 OUR_PMLog(kPMLogOverrideOn, 0, 0);
2758 fDeviceOverrides = true;
2759 }
2760 else
2761 {
2762 OUR_PMLog(kPMLogOverrideOff, 0, 0);
2763 fDeviceOverrides = false;
2764 }
2765
2766 if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
2767 {
2768 computeDesiredState();
2769 changeState();
2770 }
2771 }
2772
2773 //*********************************************************************************
2774 // [private] enqueuePowerChange
2775 //*********************************************************************************
2776
2777 IOReturn IOService::enqueuePowerChange (
2778 unsigned long flags,
2779 unsigned long whatStateOrdinal,
2780 unsigned long domainState,
2781 IOPowerConnection * whichParent,
2782 unsigned long singleParentState )
2783 {
2784 changeNoteItem changeNote;
2785 IOPMPowerState * powerStatePtr;
2786
2787 PM_ASSERT_IN_GATE();
2788 assert( fMachineState == kIOPM_Finished );
2789 assert( whatStateOrdinal < fNumberOfPowerStates );
2790
2791 if (whatStateOrdinal >= fNumberOfPowerStates)
2792 return IOPMAckImplied;
2793
2794 powerStatePtr = &fPowerStates[whatStateOrdinal];
2795
2796 // Initialize the change note
2797 changeNote.flags = flags;
2798 changeNote.newStateNumber = whatStateOrdinal;
2799 changeNote.outputPowerCharacter = powerStatePtr->outputPowerCharacter;
2800 changeNote.inputPowerRequirement = powerStatePtr->inputPowerRequirement;
2801 changeNote.capabilityFlags = powerStatePtr->capabilityFlags;
2802 changeNote.parent = NULL;
2803
2804 if (flags & IOPMParentInitiated )
2805 {
2806 changeNote.domainState = domainState;
2807 changeNote.parent = whichParent;
2808 changeNote.singleParentState = singleParentState;
2809 }
2810
2811 if (flags & IOPMWeInitiated )
2812 {
2813 start_our_change(&changeNote);
2814 return 0;
2815 }
2816 else
2817 {
2818 return start_parent_change(&changeNote);
2819 }
2820 }
2821
2822 //*********************************************************************************
2823 // [private] notifyInterestedDrivers
2824 //*********************************************************************************
2825
2826 bool IOService::notifyInterestedDrivers ( void )
2827 {
2828 IOPMinformee * informee;
2829 IOPMinformeeList * list = fInterestedDrivers;
2830 DriverCallParam * param;
2831 IOItemCount count;
2832
2833 PM_ASSERT_IN_GATE();
2834 assert( fDriverCallBusy == false );
2835 assert( fDriverCallParamCount == 0 );
2836 assert( fHeadNotePendingAcks == 0 );
2837
2838 count = list->numberOfItems();
2839 if (!count)
2840 goto done; // no interested drivers
2841
2842 // Allocate an array of interested drivers and their return values
2843 // for the callout thread. Everything else is still "owned" by the
2844 // PM work loop, which can run to process acknowledgePowerChange()
2845 // responses.
2846
2847 param = (DriverCallParam *) fDriverCallParamPtr;
2848 if (count > fDriverCallParamSlots)
2849 {
2850 if (fDriverCallParamSlots)
2851 {
2852 assert(fDriverCallParamPtr);
2853 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
2854 fDriverCallParamPtr = 0;
2855 fDriverCallParamSlots = 0;
2856 }
2857
2858 param = IONew(DriverCallParam, count);
2859 if (!param)
2860 goto done; // no memory
2861
2862 fDriverCallParamPtr = (void *) param;
2863 fDriverCallParamSlots = count;
2864 }
2865
2866 informee = list->firstInList();
2867 assert(informee);
2868 for (IOItemCount i = 0; i < count; i++)
2869 {
2870 informee->timer = -1;
2871 param[i].Target = informee;
2872 informee->retain();
2873 informee = list->nextInList( informee );
2874 }
2875
2876 fDriverCallParamCount = count;
2877 fHeadNotePendingAcks = count;
2878
2879 // Machine state will be blocked pending callout thread completion.
2880
2881 PM_LOCK();
2882 fDriverCallBusy = true;
2883 PM_UNLOCK();
2884 thread_call_enter( fDriverCallEntry );
2885 return true;
2886
2887 done:
2888 // no interested drivers or did not schedule callout thread due to error.
2889 return false;
2890 }
2891
2892 //*********************************************************************************
2893 // [private] notifyInterestedDriversDone
2894 //*********************************************************************************
2895
2896 void IOService::notifyInterestedDriversDone ( void )
2897 {
2898 IOPMinformee * informee;
2899 IOItemCount count;
2900 DriverCallParam * param;
2901 IOReturn result;
2902
2903 PM_ASSERT_IN_GATE();
2904 param = (DriverCallParam *) fDriverCallParamPtr;
2905 count = fDriverCallParamCount;
2906
2907 assert( fDriverCallBusy == false );
2908 assert( fMachineState == kIOPM_DriverThreadCallDone );
2909
2910 if (param && count)
2911 {
2912 for (IOItemCount i = 0; i < count; i++, param++)
2913 {
2914 informee = (IOPMinformee *) param->Target;
2915 result = param->Result;
2916
2917 if ((result == IOPMAckImplied) || (result < 0))
2918 {
2919 // child return IOPMAckImplied
2920 informee->timer = 0;
2921 fHeadNotePendingAcks--;
2922 }
2923 else if (informee->timer)
2924 {
2925 assert(informee->timer == -1);
2926
2927 // Driver has not acked, and has returned a positive result.
2928 // Enforce a minimum permissible timeout value.
2929 // Make the min value large enough so timeout is less likely
2930 // to occur if a driver misinterpreted that the return value
2931 // should be in microsecond units. And make it large enough
2932 // to be noticeable if a driver neglects to ack.
2933
2934 if (result < kMinAckTimeoutTicks)
2935 result = kMinAckTimeoutTicks;
2936
2937 informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
2938 }
2939 // else, child has already acked or driver has removed interest,
2940 // and head_note_pendingAcks decremented.
2941 // informee may have been removed from the interested drivers list,
2942 // thus the informee must be retained across the callout.
2943
2944 informee->release();
2945 }
2946
2947 fDriverCallParamCount = 0;
2948
2949 if ( fHeadNotePendingAcks )
2950 {
2951 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
2952 start_ack_timer();
2953 }
2954 }
2955
2956 // Hop back to original machine state path (from notifyAll)
2957 fMachineState = fNextMachineState;
2958
2959 notifyChildren();
2960 }
2961
2962 //*********************************************************************************
2963 // [private] notifyChildren
2964 //*********************************************************************************
2965
2966 void IOService::notifyChildren ( void )
2967 {
2968 OSIterator * iter;
2969 OSObject * next;
2970 IOPowerConnection * connection;
2971 OSArray * children = 0;
2972
2973 if (fStrictTreeOrder)
2974 children = OSArray::withCapacity(8);
2975
2976 // Sum child power consumption in notifyChild()
2977 fPowerStates[fHeadNoteState].staticPower = 0;
2978
2979 iter = getChildIterator(gIOPowerPlane);
2980 if ( iter )
2981 {
2982 while ((next = iter->getNextObject()))
2983 {
2984 if ((connection = OSDynamicCast(IOPowerConnection, next)))
2985 {
2986 if (connection->getReadyFlag() == false)
2987 {
2988 PM_CONNECT("[%s] %s: connection not ready\n",
2989 getName(), __FUNCTION__);
2990 continue;
2991 }
2992
2993 if (children)
2994 children->setObject( connection );
2995 else
2996 notifyChild( connection,
2997 fDriverCallReason == kDriverCallInformPreChange );
2998 }
2999 }
3000 iter->release();
3001 }
3002
3003 if (children)
3004 {
3005 if (children->getCount() == 0)
3006 {
3007 children->release();
3008 children = 0;
3009 }
3010 else
3011 {
3012 assert(fNotifyChildArray == 0);
3013 fNotifyChildArray = children;
3014 fNextMachineState = fMachineState;
3015 fMachineState = kIOPM_NotifyChildrenDone;
3016 }
3017 }
3018 }
3019
3020 //*********************************************************************************
3021 // [private] notifyChildrenDone
3022 //*********************************************************************************
3023
3024 void IOService::notifyChildrenDone ( void )
3025 {
3026 PM_ASSERT_IN_GATE();
3027 assert(fNotifyChildArray);
3028 assert(fMachineState == kIOPM_NotifyChildrenDone);
3029
3030 // Interested drivers have all acked (if any), ack timer stopped.
3031 // Notify one child, wait for it's ack, then repeat for next child.
3032 // This is a workaround for some drivers with multiple instances at
3033 // the same branch in the power tree, but the driver is slow to power
3034 // up unless the tree ordering is observed. Problem observed only on
3035 // system wake, not on system sleep.
3036 //
3037 // We have the ability to power off in reverse child index order.
3038 // That works nicely on some machines, but not on all HW configs.
3039
3040 if (fNotifyChildArray->getCount())
3041 {
3042 IOPowerConnection * connection;
3043 connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
3044 fNotifyChildArray->removeObject(0);
3045 notifyChild( connection, fDriverCallReason == kDriverCallInformPreChange );
3046 }
3047 else
3048 {
3049 fNotifyChildArray->release();
3050 fNotifyChildArray = 0;
3051 fMachineState = fNextMachineState;
3052 }
3053 }
3054
3055 //*********************************************************************************
3056 // [private] notifyAll
3057 //*********************************************************************************
3058
3059 IOReturn IOService::notifyAll ( bool is_prechange )
3060 {
3061 // Save the next machine_state to be restored by notifyInterestedDriversDone()
3062
3063 PM_ASSERT_IN_GATE();
3064 fNextMachineState = fMachineState;
3065 fMachineState = kIOPM_DriverThreadCallDone;
3066 fDriverCallReason = is_prechange ?
3067 kDriverCallInformPreChange : kDriverCallInformPostChange;
3068
3069 if (!notifyInterestedDrivers())
3070 notifyInterestedDriversDone();
3071
3072 return IOPMWillAckLater;
3073 }
3074
3075 //*********************************************************************************
3076 // [private, static] pmDriverCallout
3077 //
3078 // Thread call context
3079 //*********************************************************************************
3080
3081 IOReturn IOService::actionDriverCalloutDone (
3082 OSObject * target,
3083 void * arg0, void * arg1,
3084 void * arg2, void * arg3 )
3085 {
3086 IOServicePM * pwrMgt = (IOServicePM *) arg0;
3087
3088 PM_LOCK();
3089 fDriverCallBusy = false;
3090 PM_UNLOCK();
3091
3092 if (gIOPMReplyQueue)
3093 gIOPMReplyQueue->signalWorkAvailable();
3094
3095 return kIOReturnSuccess;
3096 }
3097
3098 void IOService::pmDriverCallout ( IOService * from )
3099 {
3100 assert(from);
3101 switch (from->fDriverCallReason)
3102 {
3103 case kDriverCallSetPowerState:
3104 from->driverSetPowerState();
3105 break;
3106
3107 case kDriverCallInformPreChange:
3108 case kDriverCallInformPostChange:
3109 from->driverInformPowerChange();
3110 break;
3111
3112 default:
3113 IOPanic("IOService::pmDriverCallout bad machine state");
3114 }
3115
3116 gIOPMWorkLoop->runAction(actionDriverCalloutDone,
3117 /* target */ from,
3118 /* arg0 */ (void *) from->pwrMgt );
3119 }
3120
3121 //*********************************************************************************
3122 // [private] driverSetPowerState
3123 //
3124 // Thread call context
3125 //*********************************************************************************
3126
3127 void IOService::driverSetPowerState ( void )
3128 {
3129 IOService * driver;
3130 unsigned long powerState;
3131 DriverCallParam * param;
3132 IOReturn result;
3133 AbsoluteTime end;
3134
3135 assert( fDriverCallBusy );
3136 param = (DriverCallParam *) fDriverCallParamPtr;
3137 assert( param );
3138 assert( fDriverCallParamCount == 1 );
3139
3140 driver = fControllingDriver;
3141 powerState = fHeadNoteState;
3142
3143 if (!fWillPMStop)
3144 {
3145 OUR_PMLog( kPMLogProgramHardware, (UInt32) this, powerState);
3146 clock_get_uptime(&fDriverCallStartTime);
3147 result = driver->setPowerState( powerState, this );
3148 clock_get_uptime(&end);
3149 OUR_PMLog((UInt32) -kPMLogProgramHardware, (UInt32) this, (UInt32) result);
3150
3151 #if LOG_SETPOWER_TIMES
3152 if ((result == IOPMAckImplied) || (result < 0))
3153 {
3154 uint64_t nsec;
3155
3156 SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
3157 absolutetime_to_nanoseconds(end, &nsec);
3158 if (nsec > LOG_SETPOWER_TIMES)
3159 PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
3160 fName, this, fCurrentPowerState, powerState, NS_TO_MS(nsec));
3161 }
3162 #endif
3163 }
3164 else
3165 result = kIOPMAckImplied;
3166
3167 param->Result = result;
3168 }
3169
3170 //*********************************************************************************
3171 // [private] driverInformPowerChange
3172 //
3173 // Thread call context
3174 //*********************************************************************************
3175
3176 void IOService::driverInformPowerChange ( void )
3177 {
3178 IOItemCount count;
3179 IOPMinformee * informee;
3180 IOService * driver;
3181 IOReturn result;
3182 IOPMPowerFlags powerFlags;
3183 unsigned long powerState;
3184 DriverCallParam * param;
3185 AbsoluteTime end;
3186
3187 assert( fDriverCallBusy );
3188 param = (DriverCallParam *) fDriverCallParamPtr;
3189 count = fDriverCallParamCount;
3190 assert( count && param );
3191
3192 powerFlags = fHeadNoteCapabilityFlags;
3193 powerState = fHeadNoteState;
3194
3195 for (IOItemCount i = 0; i < count; i++)
3196 {
3197 informee = (IOPMinformee *) param->Target;
3198 driver = informee->whatObject;
3199
3200 if (!fWillPMStop && informee->active)
3201 {
3202 if (fDriverCallReason == kDriverCallInformPreChange)
3203 {
3204 OUR_PMLog(kPMLogInformDriverPreChange, (UInt32) this, powerState);
3205 clock_get_uptime(&informee->startTime);
3206 result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
3207 clock_get_uptime(&end);
3208 OUR_PMLog((UInt32)-kPMLogInformDriverPreChange, (UInt32) this, result);
3209 }
3210 else
3211 {
3212 OUR_PMLog(kPMLogInformDriverPostChange, (UInt32) this, powerState);
3213 clock_get_uptime(&informee->startTime);
3214 result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
3215 clock_get_uptime(&end);
3216 OUR_PMLog((UInt32)-kPMLogInformDriverPostChange, (UInt32) this, result);
3217 }
3218
3219 #if LOG_SETPOWER_TIMES
3220 if ((result == IOPMAckImplied) || (result < 0))
3221 {
3222 uint64_t nsec;
3223
3224 SUB_ABSOLUTETIME(&end, &informee->startTime);
3225 absolutetime_to_nanoseconds(end, &nsec);
3226 if (nsec > LOG_SETPOWER_TIMES)
3227 PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
3228 driver->getName(),
3229 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
3230 driver, fName, fCurrentPowerState, powerState, NS_TO_MS(nsec));
3231 }
3232 #endif
3233 }
3234 else
3235 result = kIOPMAckImplied;
3236
3237 param->Result = result;
3238 param++;
3239 }
3240 }
3241
3242 //*********************************************************************************
3243 // [private] notifyChild
3244 //
3245 // Notify a power domain child of an upcoming power change.
3246 // If the object acknowledges the current change, we return TRUE.
3247 //*********************************************************************************
3248
3249 bool IOService::notifyChild ( IOPowerConnection * theNub, bool is_prechange )
3250 {
3251 IOReturn k = IOPMAckImplied;
3252 unsigned long childPower;
3253 IOService * theChild;
3254 IOPMRequest * childRequest;
3255 int requestType;
3256
3257 PM_ASSERT_IN_GATE();
3258 theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
3259 if (!theChild)
3260 {
3261 assert(false);
3262 return true;
3263 }
3264
3265 // Unless the child handles the notification immediately and returns
3266 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
3267 fHeadNotePendingAcks++;
3268 theNub->setAwaitingAck(true);
3269
3270 requestType = is_prechange ?
3271 kIOPMRequestTypePowerDomainWillChange :
3272 kIOPMRequestTypePowerDomainDidChange;
3273
3274 childRequest = acquirePMRequest( theChild, requestType );
3275 if (childRequest)
3276 {
3277 theNub->retain();
3278 childRequest->fArg0 = (void *) fHeadNoteOutputFlags;
3279 childRequest->fArg1 = (void *) theNub;
3280 childRequest->fArg2 = (void *) (fHeadNoteState < fCurrentPowerState);
3281 theChild->submitPMRequest( childRequest );
3282 k = IOPMWillAckLater;
3283 }
3284 else
3285 {
3286 k = IOPMAckImplied;
3287 fHeadNotePendingAcks--;
3288 theNub->setAwaitingAck(false);
3289 childPower = theChild->currentPowerConsumption();
3290 if ( childPower == kIOPMUnknown )
3291 {
3292 fPowerStates[fHeadNoteState].staticPower = kIOPMUnknown;
3293 } else {
3294 if ( fPowerStates[fHeadNoteState].staticPower != kIOPMUnknown )
3295 {
3296 fPowerStates[fHeadNoteState].staticPower += childPower;
3297 }
3298 }
3299 }
3300
3301 theChild->release();
3302 return (k == IOPMAckImplied);
3303 }
3304
3305 //*********************************************************************************
3306 // [private] OurChangeTellClientsPowerDown
3307 //
3308 // All registered applications and kernel clients have positively acknowledged our
3309 // intention of lowering power. Here we notify them all that we will definitely
3310 // lower the power. If we don't have to wait for any of them to acknowledge, we
3311 // carry on by notifying interested drivers. Otherwise, we do wait.
3312 //*********************************************************************************
3313
3314 void IOService::OurChangeTellClientsPowerDown ( void )
3315 {
3316 fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
3317 tellChangeDown1(fHeadNoteState);
3318 }
3319
3320 //*********************************************************************************
3321 // [private] OurChangeTellPriorityClientsPowerDown
3322 //
3323 // All registered applications and kernel clients have positively acknowledged our
3324 // intention of lowering power. Here we notify "priority" clients that we are
3325 // lowering power. If we don't have to wait for any of them to acknowledge, we
3326 // carry on by notifying interested drivers. Otherwise, we do wait.
3327 //*********************************************************************************
3328
3329 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
3330 {
3331 fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
3332 tellChangeDown2(fHeadNoteState);
3333 }
3334
3335 //*********************************************************************************
3336 // [private] OurChangeNotifyInterestedDriversWillChange
3337 //
3338 // All registered applications and kernel clients have acknowledged our notification
3339 // that we are lowering power. Here we notify interested drivers. If we don't have
3340 // to wait for any of them to acknowledge, we instruct our power driver to make the
3341 // change. Otherwise, we do wait.
3342 //*********************************************************************************
3343
3344 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
3345 {
3346 fMachineState = kIOPM_OurChangeSetPowerState;
3347 notifyAll( true );
3348 }
3349
3350 //*********************************************************************************
3351 // [private] OurChangeSetPowerState
3352 //
3353 // All interested drivers have acknowledged our pre-change notification of a power
3354 // change we initiated. Here we instruct our controlling driver to make
3355 // the change to the hardware. If it does so, we continue processing
3356 // (waiting for settle and notifying interested parties post-change.)
3357 // If it doesn't, we have to wait for it to acknowledge and then continue.
3358 //*********************************************************************************
3359
3360 void IOService::OurChangeSetPowerState ( void )
3361 {
3362 fNextMachineState = kIOPM_OurChangeWaitForPowerSettle;
3363 fMachineState = kIOPM_DriverThreadCallDone;
3364 fDriverCallReason = kDriverCallSetPowerState;
3365
3366 if (notifyControllingDriver() == false)
3367 notifyControllingDriverDone();
3368 }
3369
3370 //*********************************************************************************
3371 // [private] OurChangeWaitForPowerSettle
3372 //
3373 // Our controlling driver has changed power state on the hardware
3374 // during a power change we initiated. Here we see if we need to wait
3375 // for power to settle before continuing. If not, we continue processing
3376 // (notifying interested parties post-change). If so, we wait and
3377 // continue later.
3378 //*********************************************************************************
3379
3380 void IOService::OurChangeWaitForPowerSettle ( void )
3381 {
3382 fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
3383 fSettleTimeUS = compute_settle_time();
3384 if ( fSettleTimeUS )
3385 {
3386 startSettleTimer(fSettleTimeUS);
3387 }
3388 }
3389
3390 //*********************************************************************************
3391 // [private] OurChangeNotifyInterestedDriversDidChange
3392 //
3393 // Power has settled on a power change we initiated. Here we notify
3394 // all our interested parties post-change. If they all acknowledge, we're
3395 // done with this change note, and we can start on the next one.
3396 // Otherwise we have to wait for acknowledgements and finish up later.
3397 //*********************************************************************************
3398
3399 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
3400 {
3401 fMachineState = kIOPM_OurChangeFinish;
3402 notifyAll(false);
3403 }
3404
3405 //*********************************************************************************
3406 // [private] OurChangeFinish
3407 //
3408 // Power has settled on a power change we initiated, and
3409 // all our interested parties have acknowledged. We're
3410 // done with this change note, and we can start on the next one.
3411 //*********************************************************************************
3412
3413 void IOService::OurChangeFinish ( void )
3414 {
3415 all_done();
3416 }
3417
3418 //*********************************************************************************
3419 // [private] ParentDownTellPriorityClientsPowerDown
3420 //
3421 // All applications and kernel clients have been notified of a power lowering
3422 // initiated by the parent and we had to wait for responses. Here
3423 // we notify any priority clients. If they all ack, we continue with the power change.
3424 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
3425 //*********************************************************************************
3426
3427 void IOService::ParentDownTellPriorityClientsPowerDown ( void )
3428 {
3429 fMachineState = kIOPM_ParentDownNotifyInterestedDriversWillChange;
3430 tellChangeDown2(fHeadNoteState);
3431 }
3432
3433 //*********************************************************************************
3434 // [private] ParentDownNotifyInterestedDriversWillChange
3435 //
3436 // All applications and kernel clients have been notified of a power lowering
3437 // initiated by the parent and we had to wait for their responses. Here we notify
3438 // any interested drivers and power domain children. If they all ack, we continue
3439 // with the power change.
3440 // If at least one doesn't, we have to wait for it to acknowledge and then continue.
3441 //*********************************************************************************
3442
3443 void IOService::ParentDownNotifyInterestedDriversWillChange ( void )
3444 {
3445 fMachineState = kIOPM_ParentDownSetPowerState;
3446 notifyAll( true );
3447 }
3448
3449 //*********************************************************************************
3450 // [private] ParentDownSetPowerState
3451 //
3452 // We had to wait for it, but all parties have acknowledged our pre-change
3453 // notification of a power lowering initiated by the parent.
3454 // Here we instruct our controlling driver
3455 // to put the hardware in the state it needs to be in when the domain is
3456 // lowered. If it does so, we continue processing
3457 // (waiting for settle and acknowledging the parent.)
3458 // If it doesn't, we have to wait for it to acknowledge and then continue.
3459 //*********************************************************************************
3460
3461 void IOService::ParentDownSetPowerState ( void )
3462 {
3463 fNextMachineState = kIOPM_ParentDownWaitForPowerSettle;
3464 fMachineState = kIOPM_DriverThreadCallDone;
3465 fDriverCallReason = kDriverCallSetPowerState;
3466
3467 if (notifyControllingDriver() == false)
3468 notifyControllingDriverDone();
3469 }
3470
3471 //*********************************************************************************
3472 // [private] ParentDownWaitForPowerSettle
3473 //
3474 // Our controlling driver has changed power state on the hardware
3475 // during a power change initiated by our parent. We have had to wait
3476 // for acknowledgement from interested parties, or we have had to wait
3477 // for the controlling driver to change the state. Here we see if we need
3478 // to wait for power to settle before continuing. If not, we continue
3479 // processing (acknowledging our preparedness to the parent).
3480 // If so, we wait and continue later.
3481 //*********************************************************************************
3482
3483 void IOService::ParentDownWaitForPowerSettle ( void )
3484 {
3485 fMachineState = kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange;
3486 fSettleTimeUS = compute_settle_time();
3487 if ( fSettleTimeUS )
3488 {
3489 startSettleTimer(fSettleTimeUS);
3490 }
3491 }
3492
3493 //*********************************************************************************
3494 // [private] ParentDownNotifyDidChangeAndAcknowledgeChange
3495 //
3496 // Power has settled on a power change initiated by our parent. Here we
3497 // notify interested parties.
3498 //*********************************************************************************
3499
3500 void IOService::ParentDownNotifyDidChangeAndAcknowledgeChange ( void )
3501 {
3502 fMachineState = kIOPM_ParentDownAcknowledgeChange;
3503 notifyAll(false);
3504 }
3505
3506 //*********************************************************************************
3507 // [private] ParentDownAcknowledgeChange
3508 //
3509 // We had to wait for it, but all parties have acknowledged our post-change
3510 // notification of a power lowering initiated by the parent.
3511 // Here we acknowledge the parent.
3512 // We are done with this change note, and we can start on the next one.
3513 //*********************************************************************************
3514
3515 void IOService::ParentDownAcknowledgeChange ( void )
3516 {
3517 IORegistryEntry * nub;
3518 IOService * parent;
3519
3520 nub = fHeadNoteParent;
3521 nub->retain();
3522 all_done();
3523 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
3524 if ( parent )
3525 {
3526 parent->acknowledgePowerChange((IOService *)nub);
3527 parent->release();
3528 }
3529 nub->release();
3530 }
3531
3532 //*********************************************************************************
3533 // [private] ParentUpSetPowerState
3534 //
3535 // Our parent has informed us via powerStateDidChange that it has
3536 // raised the power in our power domain, and we have had to wait
3537 // for some interested party to acknowledge our notification.
3538 // Here we instruct our controlling
3539 // driver to program the hardware to take advantage of the higher domain
3540 // power. If it does so, we continue processing
3541 // (waiting for settle and notifying interested parties post-change.)
3542 // If it doesn't, we have to wait for it to acknowledge and then continue.
3543 //*********************************************************************************
3544
3545 void IOService::ParentUpSetPowerState ( void )
3546 {
3547 fNextMachineState = kIOPM_ParentUpWaitForSettleTime;
3548 fMachineState = kIOPM_DriverThreadCallDone;
3549 fDriverCallReason = kDriverCallSetPowerState;
3550
3551 if (notifyControllingDriver() == false)
3552 notifyControllingDriverDone();
3553 }
3554
3555 //*********************************************************************************
3556 // [private] ParentUpWaitForSettleTime
3557 //
3558 // Our controlling driver has changed power state on the hardware
3559 // during a power raise initiated by the parent, but we had to wait for it.
3560 // Here we see if we need to wait for power to settle before continuing.
3561 // If not, we continue processing (notifying interested parties post-change).
3562 // If so, we wait and continue later.
3563 //*********************************************************************************
3564
3565 void IOService::ParentUpWaitForSettleTime ( void )
3566 {
3567 fMachineState = kIOPM_ParentUpNotifyInterestedDriversDidChange;
3568 fSettleTimeUS = compute_settle_time();
3569 if ( fSettleTimeUS )
3570 {
3571 startSettleTimer(fSettleTimeUS);
3572 }
3573 }
3574
3575 //*********************************************************************************
3576 // [private] ParentUpNotifyInterestedDriversDidChange
3577 //
3578 // Power has settled on a power raise initiated by the parent.
3579 // Here we notify all our interested parties post-change. If they all acknowledge,
3580 // we're done with this change note, and we can start on the next one.
3581 // Otherwise we have to wait for acknowledgements and finish up later.
3582 //*********************************************************************************
3583
3584 void IOService::ParentUpNotifyInterestedDriversDidChange ( void )
3585 {
3586 fMachineState = kIOPM_ParentUpAcknowledgePowerChange;
3587 notifyAll(false);
3588 }
3589
3590 //*********************************************************************************
3591 // [private] ParentUpAcknowledgePowerChange
3592 //
3593 // All parties have acknowledged our post-change notification of a power
3594 // raising initiated by the parent. Here we acknowledge the parent.
3595 // We are done with this change note, and we can start on the next one.
3596 //*********************************************************************************
3597
3598 void IOService::ParentUpAcknowledgePowerChange ( void )
3599 {
3600 IORegistryEntry * nub;
3601 IOService * parent;
3602
3603 nub = fHeadNoteParent;
3604 nub->retain();
3605 all_done();
3606 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
3607 if ( parent )
3608 {
3609 parent->acknowledgePowerChange((IOService *)nub);
3610 parent->release();
3611 }
3612 nub->release();
3613 }
3614
3615 //*********************************************************************************
3616 // [private] all_done
3617 //
3618 // A power change is complete, and the used post-change note is at
3619 // the head of the queue. Remove it and set myCurrentState to the result
3620 // of the change. Start up the next change in queue.
3621 //*********************************************************************************
3622
3623 void IOService::all_done ( void )
3624 {
3625 unsigned long previous_state;
3626
3627 fMachineState = kIOPM_Finished;
3628
3629 // our power change
3630 if ( fHeadNoteFlags & IOPMWeInitiated )
3631 {
3632 // could our driver switch to the new state?
3633 if ( !( fHeadNoteFlags & IOPMNotDone) )
3634 {
3635 // we changed, tell our parent
3636 if ( !fWeAreRoot )
3637 {
3638 ask_parent(fHeadNoteState);
3639 }
3640
3641 // yes, did power raise?
3642 if ( fCurrentPowerState < fHeadNoteState )
3643 {
3644 // yes, inform clients and apps
3645 tellChangeUp (fHeadNoteState);
3646 }
3647 previous_state = fCurrentPowerState;
3648 // either way
3649 fCurrentPowerState = fHeadNoteState;
3650 #if PM_VARS_SUPPORT
3651 fPMVars->myCurrentState = fCurrentPowerState;
3652 #endif
3653 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
3654
3655 // inform subclass policy-maker
3656 if (!fWillPMStop && fParentsKnowState)
3657 powerChangeDone(previous_state);
3658 else
3659 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
3660 }
3661 }
3662
3663 // parent's power change
3664 if ( fHeadNoteFlags & IOPMParentInitiated)
3665 {
3666 if (((fHeadNoteFlags & IOPMDomainWillChange) && (fCurrentPowerState >= fHeadNoteState)) ||
3667 ((fHeadNoteFlags & IOPMDomainDidChange) && (fCurrentPowerState < fHeadNoteState)))
3668 {
3669 // did power raise?
3670 if ( fCurrentPowerState < fHeadNoteState )
3671 {
3672 // yes, inform clients and apps
3673 tellChangeUp (fHeadNoteState);
3674 }
3675 // either way
3676 previous_state = fCurrentPowerState;
3677 fCurrentPowerState = fHeadNoteState;
3678 #if PM_VARS_SUPPORT
3679 fPMVars->myCurrentState = fCurrentPowerState;
3680 #endif
3681 fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fHeadNoteDomainState);
3682
3683 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
3684
3685 // inform subclass policy-maker
3686 if (!fWillPMStop && fParentsKnowState)
3687 powerChangeDone(previous_state);
3688 else
3689 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
3690 }
3691 }
3692
3693 if (fCurrentPowerState < fNumberOfPowerStates)
3694 {
3695 const IOPMPowerState * powerStatePtr = &fPowerStates[fCurrentPowerState];
3696
3697 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
3698 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
3699 fCurrentPowerConsumption = powerStatePtr->staticPower;
3700 }
3701
3702 // When power rises enough to satisfy the tickle's desire for more power,
3703 // the condition preventing idle-timer from dropping power is removed.
3704
3705 if (fCurrentPowerState >= fIdleTimerMinPowerState)
3706 {
3707 fIdleTimerMinPowerState = 0;
3708 }
3709 }
3710
3711 //*********************************************************************************
3712 // [public] settleTimerExpired
3713 //
3714 // Power has settled after our last change. Notify interested parties that
3715 // there is a new power state.
3716 //*********************************************************************************
3717
3718 void IOService::settleTimerExpired ( void )
3719 {
3720 fSettleTimeUS = 0;
3721 }
3722
3723 //*********************************************************************************
3724 // [private] compute_settle_time
3725 //
3726 // Compute the power-settling delay in microseconds for the
3727 // change from myCurrentState to head_note_state.
3728 //*********************************************************************************
3729
3730 unsigned long IOService::compute_settle_time ( void )
3731 {
3732 unsigned long totalTime;
3733 unsigned long i;
3734
3735 PM_ASSERT_IN_GATE();
3736
3737 // compute total time to attain the new state
3738 totalTime = 0;
3739 i = fCurrentPowerState;
3740
3741 // we're lowering power
3742 if ( fHeadNoteState < fCurrentPowerState )
3743 {
3744 while ( i > fHeadNoteState )
3745 {
3746 totalTime += fPowerStates[i].settleDownTime;
3747 i--;
3748 }
3749 }
3750
3751 // we're raising power
3752 if ( fHeadNoteState > fCurrentPowerState )
3753 {
3754 while ( i < fHeadNoteState )
3755 {
3756 totalTime += fPowerStates[i+1].settleUpTime;
3757 i++;
3758 }
3759 }
3760
3761 return totalTime;
3762 }
3763
3764 //*********************************************************************************
3765 // [private] startSettleTimer
3766 //
3767 // Enter a power-settling delay in microseconds and start a timer for that delay.
3768 //*********************************************************************************
3769
3770 IOReturn IOService::startSettleTimer ( unsigned long delay )
3771 {
3772 AbsoluteTime deadline;
3773 boolean_t pending;
3774
3775 retain();
3776 clock_interval_to_deadline(delay, kMicrosecondScale, &deadline);
3777 pending = thread_call_enter_delayed(fSettleTimer, deadline);
3778 if (pending) release();
3779
3780 return IOPMNoErr;
3781 }
3782
3783 //*********************************************************************************
3784 // [public] ackTimerTick
3785 //
3786 // The acknowledgement timeout periodic timer has ticked.
3787 // If we are awaiting acks for a power change notification,
3788 // we decrement the timer word of each interested driver which hasn't acked.
3789 // If a timer word becomes zero, we pretend the driver aknowledged.
3790 // If we are waiting for the controlling driver to change the power
3791 // state of the hardware, we decrement its timer word, and if it becomes
3792 // zero, we pretend the driver acknowledged.
3793 //
3794 // Returns true if the timer tick made it possible to advance to the next
3795 // machine state, false otherwise.
3796 //*********************************************************************************
3797
3798 void IOService::ack_timer_ticked ( void )
3799 {
3800 assert(false);
3801 }
3802
3803 bool IOService::ackTimerTick( void )
3804 {
3805 IOPMinformee * nextObject;
3806 bool done = false;
3807
3808 PM_ASSERT_IN_GATE();
3809 switch (fMachineState) {
3810 case kIOPM_OurChangeWaitForPowerSettle:
3811 case kIOPM_ParentDownWaitForPowerSettle:
3812 case kIOPM_ParentUpWaitForSettleTime:
3813 // are we waiting for controlling driver to acknowledge?
3814 if ( fDriverTimer > 0 )
3815 {
3816 // yes, decrement timer tick
3817 fDriverTimer--;
3818 if ( fDriverTimer == 0 )
3819 {
3820 // controlling driver is tardy
3821 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
3822 OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
3823 setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
3824 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
3825 fName, this, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
3826
3827 if (gIOKitDebug & kIOLogDebugPower)
3828 {
3829 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
3830 fName, this, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
3831 }
3832 else
3833 {
3834 // Unblock state machine and pretend driver has acked.
3835 done = true;
3836 }
3837 } else {
3838 // still waiting, set timer again
3839 start_ack_timer();
3840 }
3841 }
3842 break;
3843
3844 case kIOPM_OurChangeSetPowerState:
3845 case kIOPM_OurChangeFinish:
3846 case kIOPM_ParentDownSetPowerState:
3847 case kIOPM_ParentDownAcknowledgeChange:
3848 case kIOPM_ParentUpSetPowerState:
3849 case kIOPM_ParentUpAcknowledgePowerChange:
3850 case kIOPM_NotifyChildrenDone:
3851 // are we waiting for interested parties to acknowledge?
3852 if ( fHeadNotePendingAcks != 0 )
3853 {
3854 // yes, go through the list of interested drivers
3855 nextObject = fInterestedDrivers->firstInList();
3856 // and check each one
3857 while ( nextObject != NULL )
3858 {
3859 if ( nextObject->timer > 0 )
3860 {
3861 nextObject->timer--;
3862 // this one should have acked by now
3863 if ( nextObject->timer == 0 )
3864 {
3865 uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
3866 OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
3867 nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
3868 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
3869 nextObject->whatObject->getName(),
3870 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
3871 nextObject->whatObject, fName, fCurrentPowerState, fHeadNoteState,
3872 NS_TO_MS(nsec));
3873
3874 // Pretend driver has acked.
3875 fHeadNotePendingAcks--;
3876 }
3877 }
3878 nextObject = fInterestedDrivers->nextInList(nextObject);
3879 }
3880
3881 // is that the last?
3882 if ( fHeadNotePendingAcks == 0 )
3883 {
3884 // yes, we can continue
3885 done = true;
3886 } else {
3887 // no, set timer again
3888 start_ack_timer();
3889 }
3890 }
3891 break;
3892
3893 case kIOPM_ParentDownTellPriorityClientsPowerDown:
3894 case kIOPM_ParentDownNotifyInterestedDriversWillChange:
3895 case kIOPM_OurChangeTellClientsPowerDown:
3896 case kIOPM_OurChangeTellPriorityClientsPowerDown:
3897 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
3898 // apps didn't respond in time
3899 cleanClientResponses(true);
3900 OUR_PMLog(kPMLogClientTardy, 0, 1);
3901 if (fMachineState == kIOPM_OurChangeTellClientsPowerDown)
3902 {
3903 // tardy equates to veto
3904 fDoNotPowerDown = true;
3905 }
3906 done = true;
3907 break;
3908
3909 default:
3910 PM_TRACE("[%s] unexpected ack timer tick (state = %ld)\n",
3911 getName(), fMachineState);
3912 break;
3913 }
3914 return done;
3915 }
3916
3917 //*********************************************************************************
3918 // [private] start_ack_timer
3919 //*********************************************************************************
3920
3921 void IOService::start_ack_timer ( void )
3922 {
3923 start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
3924 }
3925
3926 void IOService::start_ack_timer ( UInt32 interval, UInt32 scale )
3927 {
3928 AbsoluteTime deadline;
3929 boolean_t pending;
3930
3931 clock_interval_to_deadline(interval, scale, &deadline);
3932
3933 retain();
3934 pending = thread_call_enter_delayed(fAckTimer, deadline);
3935 if (pending) release();
3936 }
3937
3938 //*********************************************************************************
3939 // [private] stop_ack_timer
3940 //*********************************************************************************
3941
3942 void IOService::stop_ack_timer ( void )
3943 {
3944 boolean_t pending;
3945
3946 pending = thread_call_cancel(fAckTimer);
3947 if (pending) release();
3948 }
3949
3950 //*********************************************************************************
3951 // [static] settleTimerExpired
3952 //
3953 // Inside PM work loop's gate.
3954 //*********************************************************************************
3955
3956 IOReturn
3957 IOService::actionAckTimerExpired (
3958 OSObject * target,
3959 void * arg0, void * arg1,
3960 void * arg2, void * arg3 )
3961 {
3962 IOService * me = (IOService *) target;
3963 bool done;
3964
3965 // done will be true if the timer tick unblocks the machine state,
3966 // otherwise no need to signal the work loop.
3967
3968 done = me->ackTimerTick();
3969 if (done && gIOPMReplyQueue)
3970 gIOPMReplyQueue->signalWorkAvailable();
3971
3972 return kIOReturnSuccess;
3973 }
3974
3975 //*********************************************************************************
3976 // ack_timer_expired
3977 //
3978 // Thread call function. Holds a retain while the callout is in flight.
3979 //*********************************************************************************
3980
3981 void
3982 IOService::ack_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
3983 {
3984 IOService * me = (IOService *) arg0;
3985
3986 if (gIOPMWorkLoop)
3987 {
3988 gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
3989 }
3990 me->release();
3991 }
3992
3993 //*********************************************************************************
3994 // settleTimerExpired
3995 //
3996 // Inside PM work loop's gate.
3997 //*********************************************************************************
3998
3999 static IOReturn
4000 settleTimerExpired (
4001 OSObject * target,
4002 void * arg0, void * arg1,
4003 void * arg2, void * arg3 )
4004 {
4005 IOService * me = (IOService *) target;
4006 me->settleTimerExpired();
4007 return kIOReturnSuccess;
4008 }
4009
4010 //*********************************************************************************
4011 // settle_timer_expired
4012 //
4013 // Thread call function. Holds a retain while the callout is in flight.
4014 //*********************************************************************************
4015
4016 static void
4017 settle_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
4018 {
4019 IOService * me = (IOService *) arg0;
4020
4021 if (gIOPMWorkLoop && gIOPMReplyQueue)
4022 {
4023 gIOPMWorkLoop->runAction(settleTimerExpired, me);
4024 gIOPMReplyQueue->signalWorkAvailable();
4025 }
4026 me->release();
4027 }
4028
4029 //*********************************************************************************
4030 // [private] start_parent_change
4031 //
4032 // Here we begin the processing of a power change initiated by our parent.
4033 //*********************************************************************************
4034
4035 IOReturn IOService::start_parent_change ( const changeNoteItem * changeNote )
4036 {
4037 fHeadNoteFlags = changeNote->flags;
4038 fHeadNoteState = changeNote->newStateNumber;
4039 fHeadNoteOutputFlags = changeNote->outputPowerCharacter;
4040 fHeadNoteDomainState = changeNote->domainState;
4041 fHeadNoteParent = changeNote->parent;
4042 fHeadNoteCapabilityFlags = changeNote->capabilityFlags;
4043
4044 PM_ASSERT_IN_GATE();
4045 OUR_PMLog( kPMLogStartParentChange, fHeadNoteState, fCurrentPowerState );
4046
4047 // Power domain is lowering power
4048 if ( fHeadNoteState < fCurrentPowerState )
4049 {
4050 setParentInfo(
4051 changeNote->singleParentState,
4052 fHeadNoteParent, true );
4053
4054 // tell apps and kernel clients
4055 fInitialChange = false;
4056 fMachineState = kIOPM_ParentDownTellPriorityClientsPowerDown;
4057 tellChangeDown1(fHeadNoteState);
4058 return IOPMWillAckLater;
4059 }
4060
4061 // Power domain is raising power
4062 if ( fHeadNoteState > fCurrentPowerState )
4063 {
4064 IOPMPowerState * powerStatePtr;
4065
4066 if ( fDesiredPowerState > fCurrentPowerState )
4067 {
4068 if ( fDesiredPowerState < fHeadNoteState )
4069 {
4070 // We power up, but not all the way
4071 fHeadNoteState = fDesiredPowerState;
4072 powerStatePtr = &fPowerStates[fHeadNoteState];
4073 fHeadNoteOutputFlags = powerStatePtr->outputPowerCharacter;
4074 fHeadNoteCapabilityFlags = powerStatePtr->capabilityFlags;
4075 OUR_PMLog(kPMLogAmendParentChange, fHeadNoteState, 0);
4076 }
4077 } else {
4078 // We don't need to change
4079 fHeadNoteState = fCurrentPowerState;
4080 powerStatePtr = &fPowerStates[fHeadNoteState];
4081 fHeadNoteOutputFlags = powerStatePtr->outputPowerCharacter;
4082 fHeadNoteCapabilityFlags = powerStatePtr->capabilityFlags;
4083 OUR_PMLog(kPMLogAmendParentChange, fHeadNoteState, 0);
4084 }
4085 }
4086
4087 if ((fHeadNoteState > fCurrentPowerState) &&
4088 (fHeadNoteFlags & IOPMDomainDidChange))
4089 {
4090 // Parent did change up - start our change up
4091 fInitialChange = false;
4092 fMachineState = kIOPM_ParentUpSetPowerState;
4093 notifyAll( true );
4094 return IOPMWillAckLater;
4095 }
4096
4097 all_done();
4098 return IOPMAckImplied;
4099 }
4100
4101 //*********************************************************************************
4102 // [private] start_our_change
4103 //
4104 // Here we begin the processing of a power change initiated by us.
4105 //*********************************************************************************
4106
4107 void IOService::start_our_change ( const changeNoteItem * changeNote )
4108 {
4109 fHeadNoteFlags = changeNote->flags;
4110 fHeadNoteState = changeNote->newStateNumber;
4111 fHeadNoteOutputFlags = changeNote->outputPowerCharacter;
4112 fHeadNoteCapabilityFlags = changeNote->capabilityFlags;
4113
4114 PM_ASSERT_IN_GATE();
4115
4116 OUR_PMLog( kPMLogStartDeviceChange, fHeadNoteState, fCurrentPowerState );
4117
4118 // can our driver switch to the new state?
4119 if (( fHeadNoteCapabilityFlags & IOPMNotAttainable ) ||
4120 ((fMaxCapability < fHeadNoteState) && (!fWeAreRoot)))
4121 {
4122 // mark the change note un-actioned
4123 fHeadNoteFlags |= IOPMNotDone;
4124
4125 // no, ask the parent to do it then
4126 if ( !fWeAreRoot )
4127 {
4128 ask_parent(fHeadNoteState);
4129 }
4130 all_done();
4131 return;
4132 }
4133
4134 if ( !fInitialChange )
4135 {
4136 if ( fHeadNoteState == fCurrentPowerState )
4137 {
4138 // we initiated a null change; forget it
4139 all_done();
4140 return;
4141 }
4142 }
4143 fInitialChange = false;
4144
4145 // dropping power?
4146 if ( fHeadNoteState < fCurrentPowerState )
4147 {
4148 // yes, in case we have to wait for acks
4149 fMachineState = kIOPM_OurChangeTellClientsPowerDown;
4150 fDoNotPowerDown = false;
4151
4152 // ask apps and kernel clients if we can drop power
4153 fOutOfBandParameter = kNotifyApps;
4154 askChangeDown(fHeadNoteState);
4155 } else {
4156 // in case they don't all ack
4157 fMachineState = kIOPM_OurChangeSetPowerState;
4158 // notify interested drivers and children
4159 notifyAll(true);
4160 }
4161 }
4162
4163 //*********************************************************************************
4164 // [private] ask_parent
4165 //
4166 // Call the power domain parent to ask for a higher power state in the domain
4167 // or to suggest a lower power state.
4168 //*********************************************************************************
4169
4170 IOReturn IOService::ask_parent ( unsigned long requestedState )
4171 {
4172 OSIterator * iter;
4173 OSObject * next;
4174 IOPowerConnection * connection;
4175 IOService * parent;
4176 const IOPMPowerState * powerStatePtr;
4177 unsigned long ourRequest;
4178
4179 PM_ASSERT_IN_GATE();
4180 if (requestedState >= fNumberOfPowerStates)
4181 return IOPMNoErr;
4182
4183 powerStatePtr = &fPowerStates[requestedState];
4184 ourRequest = powerStatePtr->inputPowerRequirement;
4185
4186 if ( powerStatePtr->capabilityFlags & (kIOPMChildClamp | kIOPMPreventIdleSleep) )
4187 {
4188 ourRequest |= kIOPMPreventIdleSleep;
4189 }
4190 if ( powerStatePtr->capabilityFlags & (kIOPMChildClamp2 | kIOPMPreventSystemSleep) )
4191 {
4192 ourRequest |= kIOPMPreventSystemSleep;
4193 }
4194
4195 // is this a new desire?
4196 if ( fPreviousRequest == ourRequest )
4197 {
4198 // no, the parent knows already, just return
4199 return IOPMNoErr;
4200 }
4201
4202 if ( fWeAreRoot )
4203 {
4204 return IOPMNoErr;
4205 }
4206 fPreviousRequest = ourRequest;
4207
4208 iter = getParentIterator(gIOPowerPlane);
4209 if ( iter )
4210 {
4211 while ( (next = iter->getNextObject()) )
4212 {
4213 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
4214 {
4215 parent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
4216 if ( parent ) {
4217 if ( parent->requestPowerDomainState(
4218 ourRequest, connection, IOPMLowestState) != IOPMNoErr )
4219 {
4220 OUR_PMLog(kPMLogRequestDenied, fPreviousRequest, 0);
4221 }
4222 parent->release();
4223 }
4224 }
4225 }
4226 iter->release();
4227 }
4228
4229 return IOPMNoErr;
4230 }
4231
4232 //*********************************************************************************
4233 // [private] notifyControllingDriver
4234 //*********************************************************************************
4235
4236 bool IOService::notifyControllingDriver ( void )
4237 {
4238 DriverCallParam * param;
4239 unsigned long powerState;
4240
4241 PM_ASSERT_IN_GATE();
4242 assert( fDriverCallBusy == false );
4243 assert( fDriverCallParamCount == 0 );
4244 assert( fControllingDriver );
4245
4246 powerState = fHeadNoteState;
4247 if (fPowerStates[powerState].capabilityFlags & IOPMNotAttainable )
4248 return false; // state not attainable
4249
4250 param = (DriverCallParam *) fDriverCallParamPtr;
4251 if (!param)
4252 {
4253 param = IONew(DriverCallParam, 1);
4254 if (!param)
4255 return false; // no memory
4256
4257 fDriverCallParamPtr = (void *) param;
4258 fDriverCallParamSlots = 1;
4259 }
4260
4261 param->Target = fControllingDriver;
4262 fDriverCallParamCount = 1;
4263
4264 fDriverTimer = -1;
4265
4266 // Machine state for this object will stall waiting for a reply
4267 // from the callout thread.
4268
4269 PM_LOCK();
4270 fDriverCallBusy = true;
4271 PM_UNLOCK();
4272 thread_call_enter( fDriverCallEntry );
4273 return true;
4274 }
4275
4276 //*********************************************************************************
4277 // [private] notifyControllingDriverDone
4278 //*********************************************************************************
4279
4280 void IOService::notifyControllingDriverDone( void )
4281 {
4282 DriverCallParam * param;
4283 IOReturn result;
4284
4285 PM_ASSERT_IN_GATE();
4286 param = (DriverCallParam *) fDriverCallParamPtr;
4287
4288 assert( fDriverCallBusy == false );
4289 assert( fMachineState == kIOPM_DriverThreadCallDone );
4290
4291 if (param)
4292 {
4293 assert(fDriverCallParamCount == 1);
4294
4295 // the return value from setPowerState()
4296 result = param->Result;
4297
4298 if ((result == IOPMAckImplied) || (result < 0))
4299 {
4300 // child return IOPMAckImplied
4301 fDriverTimer = 0;
4302 }
4303 else if (fDriverTimer)
4304 {
4305 assert(fDriverTimer == -1);
4306
4307 // Driver has not acked, and has returned a positive result.
4308 // Enforce a minimum permissible timeout value.
4309 // Make the min value large enough so timeout is less likely
4310 // to occur if a driver misinterpreted that the return value
4311 // should be in microsecond units. And make it large enough
4312 // to be noticeable if a driver neglects to ack.
4313
4314 if (result < kMinAckTimeoutTicks)
4315 result = kMinAckTimeoutTicks;
4316
4317 fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
4318 }
4319 // else, child has already acked and driver_timer reset to 0.
4320
4321 fDriverCallParamCount = 0;
4322
4323 if ( fDriverTimer )
4324 {
4325 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
4326 start_ack_timer();
4327 }
4328 }
4329
4330 // Hop back to original machine state path.
4331 fMachineState = fNextMachineState;
4332 }
4333
4334 //*********************************************************************************
4335 // [public virtual] askChangeDown
4336 //
4337 // Ask registered applications and kernel clients if we can change to a lower
4338 // power state.
4339 //
4340 // Subclass can override this to send a different message type. Parameter is
4341 // the destination state number.
4342 //
4343 // Return true if we don't have to wait for acknowledgements
4344 //*********************************************************************************
4345
4346 bool IOService::askChangeDown ( unsigned long stateNum )
4347 {
4348 return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
4349 }
4350
4351 //*********************************************************************************
4352 // [public] tellChangeDown1
4353 //
4354 // Notify registered applications and kernel clients that we are definitely
4355 // dropping power.
4356 //
4357 // Return true if we don't have to wait for acknowledgements
4358 //*********************************************************************************
4359
4360 bool IOService::tellChangeDown1 ( unsigned long stateNum )
4361 {
4362 fOutOfBandParameter = kNotifyApps;
4363 return tellChangeDown(stateNum);
4364 }
4365
4366 //*********************************************************************************
4367 // [public] tellChangeDown2
4368 //
4369 // Notify priority clients that we are definitely dropping power.
4370 //
4371 // Return true if we don't have to wait for acknowledgements
4372 //*********************************************************************************
4373
4374 bool IOService::tellChangeDown2 ( unsigned long stateNum )
4375 {
4376 fOutOfBandParameter = kNotifyPriority;
4377 return tellChangeDown(stateNum);
4378 }
4379
4380 //*********************************************************************************
4381 // [public virtual] tellChangeDown
4382 //
4383 // Notify registered applications and kernel clients that we are definitely
4384 // dropping power.
4385 //
4386 // Subclass can override this to send a different message type. Parameter is
4387 // the destination state number.
4388 //
4389 // Return true if we don't have to wait for acknowledgements
4390 //*********************************************************************************
4391
4392 bool IOService::tellChangeDown ( unsigned long stateNum )
4393 {
4394 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
4395 }
4396
4397 //*********************************************************************************
4398 // cleanClientResponses
4399 //
4400 //*********************************************************************************
4401
4402 static void logAppTimeouts ( OSObject * object, void * context)
4403 {
4404 struct context *theContext = (struct context *)context;
4405 OSObject *flag;
4406
4407 if( !OSDynamicCast( IOService, object) ) {
4408 flag = theContext->responseFlags->getObject(theContext->counter);
4409 if (kOSBooleanTrue != flag)
4410 {
4411 OSString * clientID = 0;
4412 theContext->us->messageClient(theContext->msgType, object, &clientID);
4413 PM_ERROR(theContext->errorLog, clientID ? clientID->getCStringNoCopy() : "");
4414 if (clientID)
4415 clientID->release();
4416 }
4417 theContext->counter += 1;
4418 }
4419 }
4420
4421 void IOService::cleanClientResponses ( bool logErrors )
4422 {
4423 struct context theContext;
4424
4425 if (logErrors && fResponseArray) {
4426 theContext.responseFlags = fResponseArray;
4427 theContext.serialNumber = fSerialNumber;
4428 theContext.counter = 0;
4429 theContext.msgType = kIOMessageCopyClientID;
4430 theContext.us = this;
4431 theContext.maxTimeRequested = 0;
4432 theContext.stateNumber = fHeadNoteState;
4433 theContext.stateFlags = fHeadNoteCapabilityFlags;
4434 theContext.errorLog = "PM notification timeout (%s)\n";
4435
4436 switch ( fOutOfBandParameter ) {
4437 case kNotifyApps:
4438 applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &theContext);
4439 case kNotifyPriority:
4440 default:
4441 break;
4442 }
4443 }
4444
4445 if (fResponseArray)
4446 {
4447 // get rid of this stuff
4448 fResponseArray->release();
4449 fResponseArray = NULL;
4450 }
4451
4452 return;
4453 }
4454
4455 //*********************************************************************************
4456 // [public] tellClientsWithResponse
4457 //
4458 // Notify registered applications and kernel clients that we are definitely
4459 // dropping power.
4460 //
4461 // Return true if we don't have to wait for acknowledgements
4462 //*********************************************************************************
4463
4464 bool IOService::tellClientsWithResponse ( int messageType )
4465 {
4466 struct context theContext;
4467
4468 PM_ASSERT_IN_GATE();
4469
4470 fResponseArray = OSArray::withCapacity( 1 );
4471 fSerialNumber += 1;
4472
4473 theContext.responseFlags = fResponseArray;
4474 theContext.serialNumber = fSerialNumber;
4475 theContext.counter = 0;
4476 theContext.msgType = messageType;
4477 theContext.us = this;
4478 theContext.maxTimeRequested = 0;
4479 theContext.stateNumber = fHeadNoteState;
4480 theContext.stateFlags = fHeadNoteCapabilityFlags;
4481
4482 switch ( fOutOfBandParameter ) {
4483 case kNotifyApps:
4484 applyToInterested(gIOAppPowerStateInterest,
4485 pmTellAppWithResponse, (void *)&theContext);
4486 applyToInterested(gIOGeneralInterest,
4487 pmTellClientWithResponse, (void *)&theContext);
4488 break;
4489 case kNotifyPriority:
4490 applyToInterested(gIOPriorityPowerStateInterest,
4491 pmTellClientWithResponse, (void *)&theContext);
4492 break;
4493 }
4494
4495 // do we have to wait for somebody?
4496 if ( !checkForDone() )
4497 {
4498 OUR_PMLog(kPMLogStartAckTimer,theContext.maxTimeRequested, 0);
4499 start_ack_timer( theContext.maxTimeRequested / 1000, kMillisecondScale );
4500 return false;
4501 }
4502
4503 // everybody responded
4504 fResponseArray->release();
4505 fResponseArray = NULL;
4506 // cleanClientResponses(false);
4507
4508 return true;
4509 }
4510
4511 //*********************************************************************************
4512 // [static private] pmTellAppWithResponse
4513 //
4514 // We send a message to an application, and we expect a response, so we compute a
4515 // cookie we can identify the response with.
4516 //*********************************************************************************
4517
4518 void IOService::pmTellAppWithResponse ( OSObject * object, void * context )
4519 {
4520 struct context * theContext = (struct context *) context;
4521 IOServicePM * pwrMgt = theContext->us->pwrMgt;
4522 AbsoluteTime now;
4523
4524 if( OSDynamicCast( IOService, object) )
4525 {
4526 // Automatically 'ack' in kernel clients
4527 theContext->responseFlags->setObject(theContext->counter, kOSBooleanTrue);
4528
4529 const char *who = ((IOService *) object)->getName();
4530 fPlatform->PMLog(who,
4531 kPMLogClientAcknowledge, theContext->msgType, * (UInt32 *) object);
4532 } else {
4533 UInt32 refcon = ((theContext->serialNumber & 0xFFFF)<<16)
4534 + (theContext->counter & 0xFFFF);
4535 OUR_PMLog(kPMLogAppNotify, theContext->msgType, refcon);
4536
4537 #if LOG_APP_RESPONSE_TIMES
4538 OSNumber * num;
4539 clock_get_uptime(&now);
4540 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
4541 if (num)
4542 {
4543 theContext->responseFlags->setObject(theContext->counter, num);
4544 num->release();
4545 }
4546 else
4547 #endif
4548 theContext->responseFlags->setObject(theContext->counter, kOSBooleanFalse);
4549
4550 theContext->us->messageClient(theContext->msgType, object, (void *)refcon);
4551 if ( theContext->maxTimeRequested < k30seconds )
4552 {
4553 theContext->maxTimeRequested = k30seconds;
4554 }
4555
4556 theContext->counter += 1;
4557 }
4558 }
4559
4560 //*********************************************************************************
4561 // [static private] pmTellClientWithResponse
4562 //
4563 // We send a message to an in-kernel client, and we expect a response, so we compute a
4564 // cookie we can identify the response with.
4565 // If it doesn't understand the notification (it is not power-management savvy)
4566 // we won't wait for it to prepare for sleep. If it tells us via a return code
4567 // in the passed struct that it is currently ready, we won't wait for it to prepare.
4568 // If it tells us via the return code in the struct that it does need time, we will chill.
4569 //*********************************************************************************
4570
4571 void IOService::pmTellClientWithResponse ( OSObject * object, void * context )
4572 {
4573 struct context *theContext = (struct context *)context;
4574 IOPowerStateChangeNotification notify;
4575 UInt32 refcon;
4576 IOReturn retCode;
4577 OSObject *theFlag;
4578
4579 refcon = ((theContext->serialNumber & 0xFFFF)<<16) + (theContext->counter & 0xFFFF);
4580 theContext->responseFlags->setObject(theContext->counter, kOSBooleanFalse);
4581
4582 IOServicePM * pwrMgt = theContext->us->pwrMgt;
4583 if (gIOKitDebug & kIOLogPower) {
4584 OUR_PMLog(kPMLogClientNotify, refcon, (UInt32) theContext->msgType);
4585 if (OSDynamicCast(IOService, object)) {
4586 const char *who = ((IOService *) object)->getName();
4587 fPlatform->PMLog(who,
4588 kPMLogClientNotify, * (UInt32 *) object, (UInt32) object);
4589 } else if (OSDynamicCast(_IOServiceInterestNotifier, object)) {
4590 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
4591 OUR_PMLog(kPMLogClientNotify, (UInt32) n->handler, 0);
4592 }
4593 }
4594
4595 notify.powerRef = (void *)refcon;
4596 notify.returnValue = 0;
4597 notify.stateNumber = theContext->stateNumber;
4598 notify.stateFlags = theContext->stateFlags;
4599 retCode = theContext->us->messageClient(theContext->msgType,object,(void *)&notify);
4600 if ( retCode == kIOReturnSuccess )
4601 {
4602 if ( notify.returnValue == 0 )
4603 {
4604 // client doesn't want time to respond
4605 theContext->responseFlags->replaceObject(theContext->counter, kOSBooleanTrue);
4606 OUR_PMLog(kPMLogClientAcknowledge, refcon, (UInt32) object);
4607 } else {
4608 // it does want time, and it hasn't responded yet
4609 theFlag = theContext->responseFlags->getObject(theContext->counter);
4610 if ( kOSBooleanTrue != theFlag )
4611 {
4612 // so note its time requirement
4613 if ( theContext->maxTimeRequested < notify.returnValue )
4614 {
4615 theContext->maxTimeRequested = notify.returnValue;
4616 }
4617 }
4618 }
4619 } else {
4620 OUR_PMLog(kPMLogClientAcknowledge, refcon, 0);
4621 // not a client of ours
4622 // so we won't be waiting for response
4623 theContext->responseFlags->replaceObject(theContext->counter, kOSBooleanTrue);
4624 }
4625 theContext->counter += 1;
4626 }
4627
4628 //*********************************************************************************
4629 // [public virtual] tellNoChangeDown
4630 //
4631 // Notify registered applications and kernel clients that we are not
4632 // dropping power.
4633 //
4634 // Subclass can override this to send a different message type. Parameter is
4635 // the aborted destination state number.
4636 //*********************************************************************************
4637
4638 void IOService::tellNoChangeDown ( unsigned long )
4639 {
4640 return tellClients( kIOMessageDeviceWillNotPowerOff );
4641 }
4642
4643 //*********************************************************************************
4644 // [public virtual] tellChangeUp
4645 //
4646 // Notify registered applications and kernel clients that we are raising power.
4647 //
4648 // Subclass can override this to send a different message type. Parameter is
4649 // the aborted destination state number.
4650 //*********************************************************************************
4651
4652 void IOService::tellChangeUp ( unsigned long )
4653 {
4654 return tellClients( kIOMessageDeviceHasPoweredOn );
4655 }
4656
4657 //*********************************************************************************
4658 // [public] tellClients
4659 //
4660 // Notify registered applications and kernel clients of something.
4661 //*********************************************************************************
4662
4663 void IOService::tellClients ( int messageType )
4664 {
4665 struct context theContext;
4666
4667 theContext.msgType = messageType;
4668 theContext.us = this;
4669 theContext.stateNumber = fHeadNoteState;
4670 theContext.stateFlags = fHeadNoteCapabilityFlags;
4671
4672 applyToInterested(gIOPriorityPowerStateInterest,tellClient,(void *)&theContext);
4673 applyToInterested(gIOAppPowerStateInterest,tellClient, (void *)&theContext);
4674 applyToInterested(gIOGeneralInterest,tellClient, (void *)&theContext);
4675 }
4676
4677 //*********************************************************************************
4678 // [global] tellClient
4679 //
4680 // Notify a registered application or kernel client of something.
4681 //*********************************************************************************
4682
4683 void tellClient ( OSObject * object, void * context )
4684 {
4685 struct context * theContext = (struct context *) context;
4686 IOPowerStateChangeNotification notify;
4687
4688 notify.powerRef = (void *) 0;
4689 notify.returnValue = 0;
4690 notify.stateNumber = theContext->stateNumber;
4691 notify.stateFlags = theContext->stateFlags;
4692
4693 theContext->us->messageClient(theContext->msgType, object, &notify);
4694 }
4695
4696 //*********************************************************************************
4697 // [private] checkForDone
4698 //*********************************************************************************
4699
4700 bool IOService::checkForDone ( void )
4701 {
4702 int i = 0;
4703 OSObject * theFlag;
4704
4705 if ( fResponseArray == NULL )
4706 {
4707 return true;
4708 }
4709
4710 for ( i = 0; ; i++ )
4711 {
4712 theFlag = fResponseArray->getObject(i);
4713 if ( theFlag == NULL )
4714 {
4715 break;
4716 }
4717 if ( kOSBooleanTrue != theFlag )
4718 {
4719 return false;
4720 }
4721 }
4722 return true;
4723 }
4724
4725 //*********************************************************************************
4726 // [public] responseValid
4727 //*********************************************************************************
4728
4729 bool IOService::responseValid ( unsigned long x, int pid )
4730 {
4731 UInt16 serialComponent;
4732 UInt16 ordinalComponent;
4733 OSObject * theFlag;
4734 unsigned long refcon = (unsigned long) x;
4735
4736 serialComponent = (refcon >> 16) & 0xFFFF;
4737 ordinalComponent = (refcon & 0xFFFF);
4738
4739 if ( serialComponent != fSerialNumber )
4740 {
4741 return false;
4742 }
4743
4744 if ( fResponseArray == NULL )
4745 {
4746 return false;
4747 }
4748
4749 theFlag = fResponseArray->getObject(ordinalComponent);
4750
4751 if ( theFlag == 0 )
4752 {
4753 return false;
4754 }
4755
4756 OSNumber * num;
4757 if ((num = OSDynamicCast(OSNumber, theFlag)))
4758 {
4759 #if LOG_APP_RESPONSE_TIMES
4760 AbsoluteTime now;
4761 AbsoluteTime start;
4762 uint64_t nsec;
4763
4764 clock_get_uptime(&now);
4765 AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
4766 SUB_ABSOLUTETIME(&now, &start);
4767 absolutetime_to_nanoseconds(now, &nsec);
4768
4769 // > 100 ms
4770 if (nsec > LOG_APP_RESPONSE_TIMES)
4771 {
4772 OSString * name = IOCopyLogNameForPID(pid);
4773 PM_DEBUG("PM response took %d ms (%s)\n", NS_TO_MS(nsec),
4774 name ? name->getCStringNoCopy() : "");
4775 if (name)
4776 name->release();
4777 }
4778 #endif
4779 theFlag = kOSBooleanFalse;
4780 }
4781
4782 if ( kOSBooleanFalse == theFlag )
4783 {
4784 fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
4785 }
4786
4787 return true;
4788 }
4789
4790 //*********************************************************************************
4791 // [public virtual] allowPowerChange
4792 //
4793 // Our power state is about to lower, and we have notified applications
4794 // and kernel clients, and one of them has acknowledged. If this is the last to do
4795 // so, and all acknowledgements are positive, we continue with the power change.
4796 //
4797 // We serialize this processing with timer expiration with a command gate on the
4798 // power management workloop, which the timer expiration is command gated to as well.
4799 //*********************************************************************************
4800
4801 IOReturn IOService::allowPowerChange ( unsigned long refcon )
4802 {
4803 IOPMRequest * request;
4804
4805 if ( !initialized )
4806 {
4807 // we're unloading
4808 return kIOReturnSuccess;
4809 }
4810
4811 request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
4812 if (!request)
4813 {
4814 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
4815 return kIOReturnNoMemory;
4816 }
4817
4818 request->fArg0 = (void *) refcon;
4819 request->fArg1 = (void *) proc_selfpid();
4820 submitPMRequest( request );
4821
4822 return kIOReturnSuccess;
4823 }
4824
4825 IOReturn serializedAllowPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
4826 {
4827 // [deprecated] public
4828 return kIOReturnUnsupported;
4829 }
4830
4831 IOReturn IOService::serializedAllowPowerChange2 ( unsigned long refcon )
4832 {
4833 // [deprecated] public
4834 return kIOReturnUnsupported;
4835 }
4836
4837 //*********************************************************************************
4838 // [public virtual] cancelPowerChange
4839 //
4840 // Our power state is about to lower, and we have notified applications
4841 // and kernel clients, and one of them has vetoed the change. If this is the last
4842 // client to respond, we abandon the power change.
4843 //
4844 // We serialize this processing with timer expiration with a command gate on the
4845 // power management workloop, which the timer expiration is command gated to as well.
4846 //*********************************************************************************
4847
4848 IOReturn IOService::cancelPowerChange ( unsigned long refcon )
4849 {
4850 IOPMRequest * request;
4851
4852 if ( !initialized )
4853 {
4854 // we're unloading
4855 return kIOReturnSuccess;
4856 }
4857
4858 request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
4859 if (!request)
4860 {
4861 PM_ERROR("%s::%s no memory\n", getName(), __FUNCTION__);
4862 return kIOReturnNoMemory;
4863 }
4864
4865 request->fArg0 = (void *) refcon;
4866 request->fArg1 = (void *) proc_selfpid();
4867 submitPMRequest( request );
4868
4869 return kIOReturnSuccess;
4870 }
4871
4872 IOReturn serializedCancelPowerChange ( OSObject *owner, void * refcon, void *, void *, void *)
4873 {
4874 // [deprecated] public
4875 return kIOReturnUnsupported;
4876 }
4877
4878 IOReturn IOService::serializedCancelPowerChange2 ( unsigned long refcon )
4879 {
4880 // [deprecated] public
4881 return kIOReturnUnsupported;
4882 }
4883
4884 #if 0
4885 //*********************************************************************************
4886 // c_PM_clamp_Timer_Expired (C Func)
4887 //
4888 // Called when our clamp timer expires...we will call the object method.
4889 //*********************************************************************************
4890
4891 static void c_PM_Clamp_Timer_Expired ( OSObject * client, IOTimerEventSource * )
4892 {
4893 if (client)
4894 ((IOService *)client)->PM_Clamp_Timer_Expired ();
4895 }
4896 #endif
4897
4898 //*********************************************************************************
4899 // PM_Clamp_Timer_Expired
4900 //
4901 // called when clamp timer expires...set power state to 0.
4902 //*********************************************************************************
4903
4904 void IOService::PM_Clamp_Timer_Expired ( void )
4905 {
4906 #if 0
4907 if ( ! initialized )
4908 {
4909 // we're unloading
4910 return;
4911 }
4912
4913 changePowerStateToPriv (0);
4914 #endif
4915 }
4916
4917 //*********************************************************************************
4918 // clampPowerOn
4919 //
4920 // Set to highest available power state for a minimum of duration milliseconds
4921 //*********************************************************************************
4922
4923 #define kFiveMinutesInNanoSeconds (300 * NSEC_PER_SEC)
4924
4925 void IOService::clampPowerOn ( unsigned long duration )
4926 {
4927 #if 0
4928 changePowerStateToPriv (fNumberOfPowerStates-1);
4929
4930 if ( pwrMgt->clampTimerEventSrc == NULL ) {
4931 pwrMgt->clampTimerEventSrc = IOTimerEventSource::timerEventSource(this,
4932 c_PM_Clamp_Timer_Expired);
4933
4934 IOWorkLoop * workLoop = getPMworkloop ();
4935
4936 if ( !pwrMgt->clampTimerEventSrc || !workLoop ||
4937 ( workLoop->addEventSource( pwrMgt->clampTimerEventSrc) != kIOReturnSuccess) ) {
4938
4939 }
4940 }
4941
4942 pwrMgt->clampTimerEventSrc->setTimeout(300*USEC_PER_SEC, USEC_PER_SEC);
4943 #endif
4944 }
4945
4946 //*********************************************************************************
4947 // [public virtual] setPowerState
4948 //
4949 // Does nothing here. This should be implemented in a subclass driver.
4950 //*********************************************************************************
4951
4952 IOReturn IOService::setPowerState (
4953 unsigned long powerStateOrdinal, IOService * whatDevice )
4954 {
4955 return IOPMNoErr;
4956 }
4957
4958 //*********************************************************************************
4959 // [public virtual] maxCapabilityForDomainState
4960 //
4961 // Finds the highest power state in the array whose input power
4962 // requirement is equal to the input parameter. Where a more intelligent
4963 // decision is possible, override this in the subclassed driver.
4964 //*********************************************************************************
4965
4966 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
4967 {
4968 int i;
4969
4970 if (fNumberOfPowerStates == 0 )
4971 {
4972 return 0;
4973 }
4974 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
4975 {
4976 if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
4977 fPowerStates[i].inputPowerRequirement )
4978 {
4979 return i;
4980 }
4981 }
4982 return 0;
4983 }
4984
4985 //*********************************************************************************
4986 // [public virtual] initialPowerStateForDomainState
4987 //
4988 // Finds the highest power state in the array whose input power
4989 // requirement is equal to the input parameter. Where a more intelligent
4990 // decision is possible, override this in the subclassed driver.
4991 //*********************************************************************************
4992
4993 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
4994 {
4995 int i;
4996
4997 if (fNumberOfPowerStates == 0 )
4998 {
4999 return 0;
5000 }
5001 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
5002 {
5003 if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
5004 fPowerStates[i].inputPowerRequirement )
5005 {
5006 return i;
5007 }
5008 }
5009 return 0;
5010 }
5011
5012 //*********************************************************************************
5013 // [public virtual] powerStateForDomainState
5014 //
5015 // Finds the highest power state in the array whose input power
5016 // requirement is equal to the input parameter. Where a more intelligent
5017 // decision is possible, override this in the subclassed driver.
5018 //*********************************************************************************
5019
5020 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
5021 {
5022 int i;
5023
5024 if (fNumberOfPowerStates == 0 )
5025 {
5026 return 0;
5027 }
5028 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
5029 {
5030 if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
5031 fPowerStates[i].inputPowerRequirement )
5032 {
5033 return i;
5034 }
5035 }
5036 return 0;
5037 }
5038
5039 //*********************************************************************************
5040 // [public virtual] didYouWakeSystem
5041 //
5042 // Does nothing here. This should be implemented in a subclass driver.
5043 //*********************************************************************************
5044
5045 bool IOService::didYouWakeSystem ( void )
5046 {
5047 return false;
5048 }
5049
5050 //*********************************************************************************
5051 // [public virtual] powerStateWillChangeTo
5052 //
5053 // Does nothing here. This should be implemented in a subclass driver.
5054 //*********************************************************************************
5055
5056 IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
5057 {
5058 return kIOPMAckImplied;
5059 }
5060
5061 //*********************************************************************************
5062 // [public virtual] powerStateDidChangeTo
5063 //
5064 // Does nothing here. This should be implemented in a subclass driver.
5065 //*********************************************************************************
5066
5067 IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
5068 {
5069 return kIOPMAckImplied;
5070 }
5071
5072 //*********************************************************************************
5073 // [public virtual] powerChangeDone
5074 //
5075 // Called from PM work loop thread.
5076 // Does nothing here. This should be implemented in a subclass policy-maker.
5077 //*********************************************************************************
5078
5079 void IOService::powerChangeDone ( unsigned long )
5080 {
5081 }
5082
5083 //*********************************************************************************
5084 // [public virtual] newTemperature
5085 //
5086 // Does nothing here. This should be implemented in a subclass driver.
5087 //*********************************************************************************
5088
5089 IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
5090 {
5091 return IOPMNoErr;
5092 }
5093
5094 //*********************************************************************************
5095 // [public virtual] systemWillShutdown
5096 //
5097 // System shutdown and restart notification.
5098 //*********************************************************************************
5099
5100 void IOService::systemWillShutdown( IOOptionBits specifier )
5101 {
5102 IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
5103 if (rootDomain)
5104 rootDomain->acknowledgeSystemWillShutdown( this );
5105 }
5106
5107 //*********************************************************************************
5108 // [private static] acquirePMRequest
5109 //*********************************************************************************
5110
5111 IOPMRequest *
5112 IOService::acquirePMRequest( IOService * target, IOOptionBits requestType )
5113 {
5114 IOPMRequest * request;
5115
5116 assert(target);
5117
5118 request = IOPMRequest::create();
5119 if (request)
5120 {
5121 request->init( target, requestType );
5122 }
5123 return request;
5124 }
5125
5126 //*********************************************************************************
5127 // [private static] releasePMRequest
5128 //*********************************************************************************
5129
5130 void IOService::releasePMRequest( IOPMRequest * request )
5131 {
5132 if (request)
5133 {
5134 request->reset();
5135 request->release();
5136 }
5137 }
5138
5139 //*********************************************************************************
5140 // [private] submitPMRequest
5141 //*********************************************************************************
5142
5143 void IOService::submitPMRequest( IOPMRequest * request )
5144 {
5145 assert( request );
5146 assert( gIOPMReplyQueue );
5147 assert( gIOPMRequestQueue );
5148
5149 PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
5150 request->getType(), request,
5151 request->getTarget(), request->getTarget()->getName(),
5152 request->fArg0, request->fArg1, request->fArg2);
5153
5154 if (request->isReply())
5155 gIOPMReplyQueue->queuePMRequest( request );
5156 else
5157 gIOPMRequestQueue->queuePMRequest( request );
5158 }
5159
5160 void IOService::submitPMRequest( IOPMRequest ** requests, IOItemCount count )
5161 {
5162 assert( requests );
5163 assert( count > 0 );
5164 assert( gIOPMRequestQueue );
5165
5166 for (IOItemCount i = 0; i < count; i++)
5167 {
5168 IOPMRequest * req = requests[i];
5169 PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
5170 req->getType(), req,
5171 req->getTarget(), req->getTarget()->getName(),
5172 req->fArg0, req->fArg1, req->fArg2);
5173 }
5174
5175 gIOPMRequestQueue->queuePMRequestChain( requests, count );
5176 }
5177
5178 //*********************************************************************************
5179 // [private] servicePMRequestQueue
5180 //*********************************************************************************
5181
5182 bool IOService::servicePMRequestQueue(
5183 IOPMRequest * request,
5184 IOPMRequestQueue * queue )
5185 {
5186 // Calling PM methods without PMinit() is not allowed, fail the requests.
5187
5188 if (!initialized)
5189 {
5190 PM_DEBUG("[%s] %s: PM not initialized\n", getName(), __FUNCTION__);
5191 goto done;
5192 }
5193
5194 // Create an IOPMWorkQueue on demand, when the initial PM request is
5195 // received.
5196
5197 if (!fPMWorkQueue)
5198 {
5199 // Allocate and attach an IOPMWorkQueue on demand to avoid taking
5200 // the work loop lock in PMinit(), which may deadlock with certain
5201 // drivers / families.
5202
5203 fPMWorkQueue = IOPMWorkQueue::create(
5204 /* target */ this,
5205 /* Work */ OSMemberFunctionCast(IOPMWorkQueue::Action, this,
5206 &IOService::servicePMRequest),
5207 /* Done */ OSMemberFunctionCast(IOPMWorkQueue::Action, this,
5208 &IOService::retirePMRequest)
5209 );
5210
5211 if (fPMWorkQueue &&
5212 (gIOPMWorkLoop->addEventSource(fPMWorkQueue) != kIOReturnSuccess))
5213 {
5214 PM_ERROR("[%s] %s: addEventSource failed\n",
5215 getName(), __FUNCTION__);
5216 fPMWorkQueue->release();
5217 fPMWorkQueue = 0;
5218 }
5219
5220 if (!fPMWorkQueue)
5221 {
5222 PM_ERROR("[%s] %s: not ready (type %02lx)\n",
5223 getName(), __FUNCTION__, request->getType());
5224 goto done;
5225 }
5226 }
5227
5228 fPMWorkQueue->queuePMRequest(request);
5229 return false; // do not signal more
5230
5231 done:
5232 gIOPMFreeQueue->queuePMRequest( request );
5233 return false; // do not signal more
5234 }
5235
5236 //*********************************************************************************
5237 // [private] servicePMFreeQueue
5238 //
5239 // Called by IOPMFreeQueue to recycle a completed request.
5240 //*********************************************************************************
5241
5242 bool IOService::servicePMFreeQueue(
5243 IOPMRequest * request,
5244 IOPMRequestQueue * queue )
5245 {
5246 bool more = request->hasParentRequest();
5247 releasePMRequest( request );
5248 return more;
5249 }
5250
5251 //*********************************************************************************
5252 // [private] retirePMRequest
5253 //
5254 // Called by IOPMWorkQueue to retire a completed request.
5255 //*********************************************************************************
5256
5257 bool IOService::retirePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
5258 {
5259 assert(request && queue);
5260
5261 PM_TRACE("[- %02lx] %p [%p %s] State %ld, Busy %ld\n",
5262 request->getType(), request, this, getName(),
5263 fMachineState, gIOPMBusyCount);
5264
5265 // Catch requests created by PM_idle_timer_expiration().
5266
5267 if ((request->getType() == kIOPMRequestTypeActivityTickle) &&
5268 (request->fArg1 == (void *) false))
5269 {
5270 // Idle timer power drop request completed.
5271 // Restart the idle timer if deviceDesire can go lower, otherwise set
5272 // a flag so we know to restart idle timer when deviceDesire goes up.
5273
5274 if (fDeviceDesire > 0)
5275 start_PM_idle_timer();
5276 else
5277 fActivityTimerStopped = true;
5278 }
5279
5280 gIOPMFreeQueue->queuePMRequest( request );
5281 return true;
5282 }
5283
5284 //*********************************************************************************
5285 // [private] isPMBlocked
5286 //
5287 // Check if machine state transition is blocked.
5288 //*********************************************************************************
5289
5290 bool IOService::isPMBlocked ( IOPMRequest * request, int count )
5291 {
5292 int reason = 0;
5293
5294 do {
5295 if (kIOPM_Finished == fMachineState)
5296 break;
5297
5298 if (kIOPM_DriverThreadCallDone == fMachineState)
5299 {
5300 // 5 = kDriverCallInformPreChange
5301 // 6 = kDriverCallInformPostChange
5302 // 7 = kDriverCallSetPowerState
5303 if (fDriverCallBusy) reason = 5 + fDriverCallReason;
5304 break;
5305 }
5306
5307 // Waiting on driver's setPowerState() timeout.
5308 if (fDriverTimer)
5309 {
5310 reason = 1; break;
5311 }
5312
5313 // Child or interested driver acks pending.
5314 if (fHeadNotePendingAcks)
5315 {
5316 reason = 2; break;
5317 }
5318
5319 // Waiting on apps or priority power interest clients.
5320 if (fResponseArray)
5321 {
5322 reason = 3; break;
5323 }
5324
5325 // Waiting on settle timer expiration.
5326 if (fSettleTimeUS)
5327 {
5328 reason = 4; break;
5329 }
5330 } while (false);
5331
5332 fWaitReason = reason;
5333
5334 if (reason)
5335 {
5336 if (count)
5337 {
5338 PM_TRACE("[B %02lx] %p [%p %s] State %ld, Reason %d\n",
5339 request->getType(), request, this, getName(),
5340 fMachineState, reason);
5341 }
5342
5343 return true;
5344 }
5345
5346 return false;
5347 }
5348
5349 //*********************************************************************************
5350 // [private] servicePMRequest
5351 //
5352 // Service a request from our work queue.
5353 //*********************************************************************************
5354
5355 bool IOService::servicePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
5356 {
5357 bool done = false;
5358 int loop = 0;
5359
5360 assert(request && queue);
5361
5362 while (isPMBlocked(request, loop++) == false)
5363 {
5364 PM_TRACE("[W %02lx] %p [%p %s] State %ld\n",
5365 request->getType(), request, this, getName(), fMachineState);
5366
5367 fPMRequest = request;
5368
5369 // Every PM machine states must be handled in one of the cases below.
5370
5371 switch ( fMachineState )
5372 {
5373 case kIOPM_Finished:
5374 executePMRequest( request );
5375 break;
5376
5377 case kIOPM_OurChangeTellClientsPowerDown:
5378 // our change, was it vetoed?
5379 if (fDesiredPowerState > fHeadNoteState)
5380 {
5381 PM_DEBUG("%s: idle cancel\n", fName);
5382 fDoNotPowerDown = true;
5383 }
5384 if (!fDoNotPowerDown)
5385 {
5386 // no, we can continue
5387 OurChangeTellClientsPowerDown();
5388 }
5389 else
5390 {
5391 // yes, rescind the warning
5392 tellNoChangeDown(fHeadNoteState);
5393 // mark the change note un-actioned
5394 fHeadNoteFlags |= IOPMNotDone;
5395 // and we're done
5396 all_done();
5397 }
5398 break;
5399
5400 case kIOPM_OurChangeTellPriorityClientsPowerDown:
5401 OurChangeTellPriorityClientsPowerDown();
5402 break;
5403
5404 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
5405 OurChangeNotifyInterestedDriversWillChange();
5406 break;
5407
5408 case kIOPM_OurChangeSetPowerState:
5409 OurChangeSetPowerState();
5410 break;
5411
5412 case kIOPM_OurChangeWaitForPowerSettle:
5413 OurChangeWaitForPowerSettle();
5414 break;
5415
5416 case kIOPM_OurChangeNotifyInterestedDriversDidChange:
5417 OurChangeNotifyInterestedDriversDidChange();
5418 break;
5419
5420 case kIOPM_OurChangeFinish:
5421 OurChangeFinish();
5422 break;
5423
5424 case kIOPM_ParentDownTellPriorityClientsPowerDown:
5425 ParentDownTellPriorityClientsPowerDown();
5426 break;
5427
5428 case kIOPM_ParentDownNotifyInterestedDriversWillChange:
5429 ParentDownNotifyInterestedDriversWillChange();
5430 break;
5431
5432 case kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange:
5433 ParentDownNotifyDidChangeAndAcknowledgeChange();
5434 break;
5435
5436 case kIOPM_ParentDownSetPowerState:
5437 ParentDownSetPowerState();
5438 break;
5439
5440 case kIOPM_ParentDownWaitForPowerSettle:
5441 ParentDownWaitForPowerSettle();
5442 break;
5443
5444 case kIOPM_ParentDownAcknowledgeChange:
5445 ParentDownAcknowledgeChange();
5446 break;
5447
5448 case kIOPM_ParentUpSetPowerState:
5449 ParentUpSetPowerState();
5450 break;
5451
5452 case kIOPM_ParentUpWaitForSettleTime:
5453 ParentUpWaitForSettleTime();
5454 break;
5455
5456 case kIOPM_ParentUpNotifyInterestedDriversDidChange:
5457 ParentUpNotifyInterestedDriversDidChange();
5458 break;
5459
5460 case kIOPM_ParentUpAcknowledgePowerChange:
5461 ParentUpAcknowledgePowerChange();
5462 break;
5463
5464 case kIOPM_DriverThreadCallDone:
5465 if (fDriverCallReason == kDriverCallSetPowerState)
5466 notifyControllingDriverDone();
5467 else
5468 notifyInterestedDriversDone();
5469 break;
5470
5471 case kIOPM_NotifyChildrenDone:
5472 notifyChildrenDone();
5473 break;
5474
5475 default:
5476 IOPanic("servicePMWorkQueue: unknown machine state");
5477 }
5478
5479 fPMRequest = 0;
5480
5481 if (fMachineState == kIOPM_Finished)
5482 {
5483 //PM_TRACE("[%s] PM End: Request %p (type %02lx)\n",
5484 // getName(), request, request->getType());
5485 done = true;
5486 break;
5487 }
5488 }
5489
5490 return done;
5491 }
5492
5493 //*********************************************************************************
5494 // [private] executePMRequest
5495 //*********************************************************************************
5496
5497 void IOService::executePMRequest( IOPMRequest * request )
5498 {
5499 assert( kIOPM_Finished == fMachineState );
5500
5501 switch (request->getType())
5502 {
5503 case kIOPMRequestTypePMStop:
5504 handlePMstop( request );
5505 break;
5506
5507 case kIOPMRequestTypeAddPowerChild1:
5508 addPowerChild1( request );
5509 break;
5510
5511 case kIOPMRequestTypeAddPowerChild2:
5512 addPowerChild2( request );
5513 break;
5514
5515 case kIOPMRequestTypeAddPowerChild3:
5516 addPowerChild3( request );
5517 break;
5518
5519 case kIOPMRequestTypeRegisterPowerDriver:
5520 handleRegisterPowerDriver( request );
5521 break;
5522
5523 case kIOPMRequestTypeAdjustPowerState:
5524 adjustPowerState();
5525 break;
5526
5527 case kIOPMRequestTypeMakeUsable:
5528 handleMakeUsable( request );
5529 break;
5530
5531 case kIOPMRequestTypeTemporaryPowerClamp:
5532 fClampOn = true;
5533 handleMakeUsable( request );
5534 break;
5535
5536 case kIOPMRequestTypePowerDomainWillChange:
5537 handlePowerDomainWillChangeTo( request );
5538 break;
5539
5540 case kIOPMRequestTypePowerDomainDidChange:
5541 handlePowerDomainDidChangeTo( request );
5542 break;
5543
5544 case kIOPMRequestTypeChangePowerStateTo:
5545 handleChangePowerStateTo( request );
5546 break;
5547
5548 case kIOPMRequestTypeChangePowerStateToPriv:
5549 handleChangePowerStateToPriv( request );
5550 break;
5551
5552 case kIOPMRequestTypePowerOverrideOnPriv:
5553 case kIOPMRequestTypePowerOverrideOffPriv:
5554 handlePowerOverrideChanged( request );
5555 break;
5556
5557 case kIOPMRequestTypeActivityTickle:
5558 if (request)
5559 {
5560 bool setDeviceDesire = false;
5561
5562 if (request->fArg1)
5563 {
5564 // Power rise from activity tickle.
5565 unsigned long ticklePowerState = (unsigned long) request->fArg0;
5566 if ((fDeviceDesire < ticklePowerState) &&
5567 (ticklePowerState < fNumberOfPowerStates))
5568 {
5569 setDeviceDesire = true;
5570 fIdleTimerMinPowerState = ticklePowerState;
5571 }
5572 }
5573 else if (fDeviceDesire > fIdleTimerMinPowerState)
5574 {
5575 // Power drop from idle timer expiration.
5576 request->fArg0 = (void *) (fDeviceDesire - 1);
5577 setDeviceDesire = true;
5578 }
5579
5580 if (setDeviceDesire)
5581 {
5582 // handleChangePowerStateToPriv() does not check the
5583 // request type, as long as the args are appropriate
5584 // for kIOPMRequestTypeChangePowerStateToPriv.
5585
5586 request->fArg1 = (void *) false;
5587 handleChangePowerStateToPriv( request );
5588 }
5589 }
5590 break;
5591
5592 default:
5593 IOPanic("executePMRequest: unknown request type");
5594 }
5595 }
5596
5597 //*********************************************************************************
5598 // [private] servicePMReplyQueue
5599 //*********************************************************************************
5600
5601 bool IOService::servicePMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
5602 {
5603 bool more = false;
5604
5605 assert( request && queue );
5606 assert( request->isReply() );
5607
5608 PM_TRACE("[A %02lx] %p [%p %s] State %ld\n",
5609 request->getType(), request, this, getName(), fMachineState);
5610
5611 switch ( request->getType() )
5612 {
5613 case kIOPMRequestTypeAllowPowerChange:
5614 case kIOPMRequestTypeCancelPowerChange:
5615 // Check if we are expecting this response.
5616 if (responseValid((unsigned long) request->fArg0, (int) request->fArg1))
5617 {
5618 if (kIOPMRequestTypeCancelPowerChange == request->getType())
5619 fDoNotPowerDown = true;
5620
5621 if (checkForDone())
5622 {
5623 stop_ack_timer();
5624 if ( fResponseArray )
5625 {
5626 fResponseArray->release();
5627 fResponseArray = NULL;
5628 }
5629 more = true;
5630 }
5631 }
5632 break;
5633
5634 case kIOPMRequestTypeAckPowerChange:
5635 more = handleAcknowledgePowerChange( request );
5636 break;
5637
5638 case kIOPMRequestTypeAckSetPowerState:
5639 if (fDriverTimer == -1)
5640 {
5641 // driver acked while setPowerState() call is in-flight.
5642 // take this ack, return value from setPowerState() is irrelevant.
5643 OUR_PMLog(kPMLogDriverAcknowledgeSet,
5644 (UInt32) this, fDriverTimer);
5645 fDriverTimer = 0;
5646 }
5647 else if (fDriverTimer > 0)
5648 {
5649 // expected ack, stop the timer
5650 stop_ack_timer();
5651
5652 #if LOG_SETPOWER_TIMES
5653 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
5654 if (nsec > LOG_SETPOWER_TIMES)
5655 PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
5656 fName, this, fCurrentPowerState, fHeadNoteState, NS_TO_MS(nsec));
5657 #endif
5658 OUR_PMLog(kPMLogDriverAcknowledgeSet, (UInt32) this, fDriverTimer);
5659 fDriverTimer = 0;
5660 more = true;
5661 }
5662 else
5663 {
5664 // unexpected ack
5665 OUR_PMLog(kPMLogAcknowledgeErr4, (UInt32) this, 0);
5666 }
5667 break;
5668
5669 case kIOPMRequestTypeInterestChanged:
5670 handleInterestChanged( request );
5671 more = true;
5672 break;
5673
5674 default:
5675 IOPanic("servicePMReplyQueue: unknown reply type");
5676 }
5677
5678 releasePMRequest( request );
5679 return more;
5680 }
5681
5682 //*********************************************************************************
5683 // IOPMRequest Class
5684 //
5685 // Requests from PM clients, and also used for inter-object messaging within PM.
5686 //*********************************************************************************
5687
5688 OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
5689
5690 IOPMRequest * IOPMRequest::create( void )
5691 {
5692 IOPMRequest * me = OSTypeAlloc(IOPMRequest);
5693 if (me && !me->init(0, kIOPMRequestTypeInvalid))
5694 {
5695 me->release();
5696 me = 0;
5697 }
5698 return me;
5699 }
5700
5701 bool IOPMRequest::init( IOService * target, IOOptionBits type )
5702 {
5703 if (!IOCommand::init())
5704 return false;
5705
5706 fType = type;
5707 fTarget = target;
5708 fParent = 0;
5709 fChildCount = 0;
5710 fArg0 = fArg1 = fArg2 = 0;
5711
5712 if (fTarget)
5713 fTarget->retain();
5714
5715 return true;
5716 }
5717
5718 void IOPMRequest::reset( void )
5719 {
5720 assert( fChildCount == 0 );
5721
5722 fType = kIOPMRequestTypeInvalid;
5723
5724 if (fParent)
5725 {
5726 fParent->fChildCount--;
5727 fParent = 0;
5728 }
5729
5730 if (fTarget)
5731 {
5732 fTarget->release();
5733 fTarget = 0;
5734 }
5735 }
5736
5737 //*********************************************************************************
5738 // IOPMRequestQueue Class
5739 //
5740 // Global queues. As PM-aware drivers load and unload, their IOPMWorkQueue's are
5741 // created and deallocated. IOPMRequestQueue are created once and never released.
5742 //*********************************************************************************
5743
5744 OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
5745
5746 IOPMRequestQueue * IOPMRequestQueue::create( IOService * inOwner, Action inAction )
5747 {
5748 IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
5749 if (me && !me->init(inOwner, inAction))
5750 {
5751 me->release();
5752 me = 0;
5753 }
5754 return me;
5755 }
5756
5757 bool IOPMRequestQueue::init( IOService * inOwner, Action inAction )
5758 {
5759 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
5760 return false;
5761
5762 queue_init(&fQueue);
5763 fLock = IOLockAlloc();
5764 return (fLock != 0);
5765 }
5766
5767 void IOPMRequestQueue::free( void )
5768 {
5769 if (fLock)
5770 {
5771 IOLockFree(fLock);
5772 fLock = 0;
5773 }
5774 return IOEventSource::free();
5775 }
5776
5777 void IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
5778 {
5779 assert(request);
5780 IOLockLock(fLock);
5781 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
5782 IOLockUnlock(fLock);
5783 if (workLoop) signalWorkAvailable();
5784 }
5785
5786 void
5787 IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
5788 {
5789 IOPMRequest * next;
5790
5791 assert(requests && count);
5792 IOLockLock(fLock);
5793 while (count--)
5794 {
5795 next = *requests;
5796 requests++;
5797 queue_enter(&fQueue, next, IOPMRequest *, fCommandChain);
5798 }
5799 IOLockUnlock(fLock);
5800 if (workLoop) signalWorkAvailable();
5801 }
5802
5803 bool IOPMRequestQueue::checkForWork( void )
5804 {
5805 Action dqAction = (Action) action;
5806 IOPMRequest * request;
5807 IOService * target;
5808 bool more = false;
5809
5810 IOLockLock( fLock );
5811
5812 while (!queue_empty(&fQueue))
5813 {
5814 queue_remove_first( &fQueue, request, IOPMRequest *, fCommandChain );
5815 IOLockUnlock( fLock );
5816 target = request->getTarget();
5817 assert(target);
5818 more |= (*dqAction)( target, request, this );
5819 IOLockLock( fLock );
5820 }
5821
5822 IOLockUnlock( fLock );
5823 return more;
5824 }
5825
5826 void IOPMRequestQueue::signalWorkAvailable( void )
5827 {
5828 IOEventSource::signalWorkAvailable();
5829 }
5830
5831 //*********************************************************************************
5832 // IOPMWorkQueue Class
5833 //
5834 // Every object in the power plane that has handled a PM request, will have an
5835 // instance of IOPMWorkQueue allocated for it.
5836 //*********************************************************************************
5837
5838 OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
5839
5840 IOPMWorkQueue *
5841 IOPMWorkQueue::create( IOService * inOwner, Action work, Action retire )
5842 {
5843 IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
5844 if (me && !me->init(inOwner, work, retire))
5845 {
5846 me->release();
5847 me = 0;
5848 }
5849 return me;
5850 }
5851
5852 bool IOPMWorkQueue::init( IOService * inOwner, Action work, Action retire )
5853 {
5854 if (!work || !retire ||
5855 !IOEventSource::init(inOwner, (IOEventSourceAction)0))
5856 return false;
5857
5858 queue_init(&fWorkQueue);
5859
5860 fWorkAction = work;
5861 fRetireAction = retire;
5862
5863 return true;
5864 }
5865
5866 void IOPMWorkQueue::queuePMRequest( IOPMRequest * request )
5867 {
5868 assert( request );
5869 assert( onThread() );
5870
5871 gIOPMBusyCount++;
5872 queue_enter(&fWorkQueue, request, IOPMRequest *, fCommandChain);
5873 checkForWork();
5874 }
5875
5876 bool IOPMWorkQueue::checkForWork( void )
5877 {
5878 IOPMRequest * request;
5879 IOService * target = (IOService *) owner;
5880 bool done;
5881
5882 while (!queue_empty(&fWorkQueue))
5883 {
5884 request = (IOPMRequest *) queue_first(&fWorkQueue);
5885 assert(request->getTarget() == target);
5886 if (request->hasChildRequest()) break;
5887 done = (*fWorkAction)( target, request, this );
5888 if (!done) break;
5889
5890 assert(gIOPMBusyCount > 0);
5891 if (gIOPMBusyCount) gIOPMBusyCount--;
5892 queue_remove_first(&fWorkQueue, request, IOPMRequest *, fCommandChain);
5893 (*fRetireAction)( target, request, this );
5894 }
5895
5896 return false;
5897 }
5898
5899 OSDefineMetaClassAndStructors(IOServicePM, OSObject)
5900
5901 //*********************************************************************************
5902 // serialize
5903 //
5904 // Serialize IOServicePM for debugging.
5905 //*********************************************************************************
5906
5907 static void
5908 setPMProperty( OSDictionary * dict, const char * key, unsigned long value )
5909 {
5910 OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
5911 if (num)
5912 {
5913 dict->setObject(key, num);
5914 num->release();
5915 }
5916 }
5917
5918 bool IOServicePM::serialize( OSSerialize * s ) const
5919 {
5920 OSDictionary * dict;
5921 bool ok = false;
5922
5923 dict = OSDictionary::withCapacity(8);
5924 if (dict)
5925 {
5926 setPMProperty( dict, "CurrentPowerState", CurrentPowerState );
5927 if (DesiredPowerState != CurrentPowerState)
5928 setPMProperty( dict, "DesiredPowerState", DesiredPowerState );
5929 if (kIOPM_Finished != MachineState)
5930 setPMProperty( dict, "MachineState", MachineState );
5931 if (ChildrenDesire)
5932 setPMProperty( dict, "ChildrenPowerState", ChildrenDesire );
5933 if (DeviceDesire)
5934 setPMProperty( dict, "DeviceChangePowerState", DeviceDesire );
5935 if (DriverDesire)
5936 setPMProperty( dict, "DriverChangePowerState", DriverDesire );
5937 if (DeviceOverrides)
5938 dict->setObject( "PowerOverrideOn", kOSBooleanTrue );
5939
5940 ok = dict->serialize(s);
5941 dict->release();
5942 }
5943
5944 return ok;
5945 }