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