1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23
24#include <IOKit/assert.h>
25#include <IOKit/IOLib.h>
26#include <IOKit/IOKitKeys.h>
27#include <IOKit/IOPlatformExpert.h>
28#include <IOKit/pwr_mgt/RootDomain.h>
29#include <IOKit/IOTimerEventSource.h>
30#include <IOKit/IOUserClient.h>
31#include <IOKit/IOHibernatePrivate.h>
32
33#include <IOKit/graphics/IOGraphicsPrivate.h>
34#include <IOKit/graphics/IOGraphicsTypesPrivate.h>
35
36#include "IODisplayWrangler.h"
37
38/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
39
40enum {
41    kIODisplayWranglerNumPowerStates = kIODisplayNumPowerStates + 1,
42    kIODisplayWranglerMaxPowerState = kIODisplayWranglerNumPowerStates - 1,
43};
44
45enum
46{
47	// seconds
48	kDimInterval          = 15,
49	kAnnoyanceWithin      = 20,
50	kMaxAnnoyanceInterval = 10 * 60,
51};
52
53/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
54
55#undef super
56#define super IOService
57
58OSDefineMetaClassAndStructors(IODisplayConnect, IOService)
59
60bool IODisplayConnect::initWithConnection( IOIndex _connection )
61{
62    char        name[ 12 ];
63
64    if (!super::init())
65        return (false);
66
67    connection = _connection;
68
69    snprintf( name, sizeof(name), "display%d", (int)connection);
70
71    setName( name);
72
73    return (true);
74}
75
76IOFramebuffer * IODisplayConnect::getFramebuffer( void )
77{
78    return ((IOFramebuffer *) getProvider());
79}
80
81IOIndex IODisplayConnect::getConnection( void )
82{
83    return (connection);
84}
85
86IOReturn  IODisplayConnect::getAttributeForConnection( IOSelect selector, uintptr_t * value )
87{
88    if (!getProvider())
89        return (kIOReturnNotReady);
90    return ((IOFramebuffer *) getProvider())->getAttributeForConnection(connection, selector, value);
91}
92
93IOReturn  IODisplayConnect::setAttributeForConnection( IOSelect selector, uintptr_t value )
94{
95    if (!getProvider())
96        return (kIOReturnNotReady);
97    return ((IOFramebuffer *) getProvider())->setAttributeForConnection(connection,  selector, value);
98}
99
100// joinPMtree
101//
102// The policy-maker in the display driver calls here when initializing.
103// We attach it into the power management hierarchy as a child of our
104// frame buffer.
105
106void IODisplayConnect::joinPMtree ( IOService * driver )
107{
108    getProvider()->addPowerChild(driver);
109}
110
111/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
112
113#define super IOService
114OSDefineMetaClassAndStructors(IODisplayWrangler, IOService);
115
116IODisplayWrangler *     gIODisplayWrangler;
117
118/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
119
120bool IODisplayWrangler::serverStart(void)
121{
122    mach_timespec_t timeout = { 120, 0 };
123
124    if (!gIODisplayWrangler)
125        waitForService(serviceMatching("IODisplayWrangler"), &timeout);
126
127    if (gIODisplayWrangler)
128    {
129        gIODisplayWrangler->fOpen = true;
130        if (gIODisplayWrangler->fMinutesToDim) gIODisplayWrangler->setIdleTimerPeriod(60);
131        gIODisplayWrangler->activityTickle(0, 0);
132    }
133
134    return (gIODisplayWrangler != 0);
135}
136
137bool IODisplayWrangler::start( IOService * provider )
138{
139    OSObject *  notify;
140
141    if (!super::start(provider))
142        return (false);
143
144    assert( gIODisplayWrangler == 0 );
145
146    setProperty(kIOUserClientClassKey, "IOAccelerationUserClient");
147
148    fMatchingLock = IOLockAlloc();
149    fFramebuffers = OSSet::withCapacity( 1 );
150    fDisplays = OSSet::withCapacity( 1 );
151
152	clock_interval_to_absolutetime_interval(kDimInterval, kSecondScale, &fDimInterval);
153
154    assert( fMatchingLock && fFramebuffers && fDisplays );
155
156    notify = addMatchingNotification( gIOPublishNotification,
157                                      serviceMatching("IODisplay"), _displayHandler,
158                                      this, fDisplays );
159    assert( notify );
160
161    notify = addMatchingNotification( gIOPublishNotification,
162                                      serviceMatching("IODisplayConnect"), _displayConnectHandler,
163                                      this, 0, 50000 );
164    assert( notify );
165
166    gIODisplayWrangler = this;
167
168    // initialize power managment
169    gIODisplayWrangler->initForPM();
170    getPMRootDomain()->publishFeature("AdaptiveDimming");
171
172    return (true);
173}
174
175bool IODisplayWrangler::_displayHandler( void * target, void * ref,
176        IOService * newService, IONotifier * notifier )
177{
178    return (((IODisplayWrangler *)target)->displayHandler((OSSet *) ref,
179            (IODisplay *) newService));
180}
181
182bool IODisplayWrangler::_displayConnectHandler( void * target, void * ref,
183        IOService * newService, IONotifier * notifier )
184{
185    return (((IODisplayWrangler *)target)->displayConnectHandler(ref,
186            (IODisplayConnect *) newService));
187}
188
189bool IODisplayWrangler::displayHandler( OSSet * set,
190                                            IODisplay * newDisplay )
191{
192    assert( OSDynamicCast( IODisplay, newDisplay ));
193
194    IOTakeLock( fMatchingLock );
195
196    set->setObject( newDisplay );
197
198    IOUnlock( fMatchingLock );
199
200    return (true);
201}
202
203bool IODisplayWrangler::displayConnectHandler( void * /* ref */,
204        IODisplayConnect * connect )
205{
206    SInt32              score = 50000;
207    OSIterator *        iter;
208    IODisplay *         display;
209    bool                found = false;
210
211    assert( OSDynamicCast( IODisplayConnect, connect ));
212
213    IOTakeLock( fMatchingLock );
214
215    iter = OSCollectionIterator::withCollection( fDisplays );
216    if (iter)
217    {
218        while (!found && (display = (IODisplay *) iter->getNextObject()))
219        {
220            if (display->getConnection())
221                continue;
222
223            do
224            {
225                if (!display->attach(connect))
226                    continue;
227                found = ((display->probe( connect, &score ))
228                         && (display->start( connect )));
229                if (!found)
230                    display->detach( connect );
231            }
232            while (false);
233        }
234        iter->release();
235    }
236
237    IOUnlock( fMatchingLock );
238
239    return (true);
240}
241
242bool IODisplayWrangler::makeDisplayConnects( IOFramebuffer * fb )
243{
244    IODisplayConnect *  connect;
245    IOItemCount         i;
246
247    for (i = 0; i < 1 /*fb->getConnectionCount()*/; i++)
248    {
249        connect = new IODisplayConnect;
250        if (0 == connect)
251            continue;
252
253        if ((connect->initWithConnection(i))
254                && (connect->attach(fb)))
255        {
256            connect->registerService( kIOServiceSynchronous );
257        }
258        connect->release();
259    }
260
261    return (true);
262}
263
264void IODisplayWrangler::destroyDisplayConnects( IOFramebuffer * fb )
265{
266    OSIterator *        iter;
267    OSObject *          next;
268    IODisplayConnect *  connect;
269    IODisplay *         display;
270
271    fb->removeProperty(kIOFBBuiltInKey);
272
273    iter = fb->getClientIterator();
274    if (iter)
275    {
276        while ((next = iter->getNextObject()))
277        {
278            if ((connect = OSDynamicCast(IODisplayConnect, next)))
279            {
280                if (connect->isInactive())
281                    continue;
282                display = OSDynamicCast( IODisplay, connect->getClient());
283                if (display)
284                {
285                    gIODisplayWrangler->fDisplays->removeObject( display );
286                    display->PMstop();
287                }
288                connect->terminate( kIOServiceSynchronous );
289            }
290        }
291        iter->release();
292    }
293}
294
295void IODisplayWrangler::activityChange( IOFramebuffer * fb )
296{
297    DEBG1("W", " activityChange\n");
298    gIODisplayWrangler->activityTickle(0,0);
299}
300
301IODisplayConnect * IODisplayWrangler::getDisplayConnect(
302    IOFramebuffer * fb, IOIndex connect )
303{
304    OSIterator  *       iter;
305    OSObject    *       next;
306    IODisplayConnect *  connection = 0;
307
308    iter = fb->getClientIterator();
309    if (iter)
310    {
311        while ((next = iter->getNextObject()))
312        {
313            connection = OSDynamicCast( IODisplayConnect, next);
314            if (connection)
315            {
316                if (connection->isInactive())
317                    continue;
318                if (0 == (connect--))
319                    break;
320            }
321        }
322        iter->release();
323    }
324    return (connection);
325}
326
327IOReturn IODisplayWrangler::getConnectFlagsForDisplayMode(
328    IODisplayConnect * connect,
329    IODisplayModeID mode, UInt32 * flags )
330{
331    IOReturn            err = kIOReturnUnsupported;
332    IODisplay *         display;
333
334    display = OSDynamicCast( IODisplay, connect->getClient());
335    if (display)
336        err = display->getConnectFlagsForDisplayMode( mode, flags );
337    else
338    {
339        err = connect->getFramebuffer()->connectFlags(
340                  connect->getConnection(), mode, flags );
341    }
342
343    return (err);
344}
345
346IOReturn IODisplayWrangler::getFlagsForDisplayMode(
347    IOFramebuffer * fb,
348    IODisplayModeID mode, UInt32 * flags )
349{
350    IODisplayConnect *          connect;
351
352    // should look at all connections
353    connect = gIODisplayWrangler->getDisplayConnect( fb, 0 );
354    if (!connect)
355        return (fb->connectFlags(0, mode, flags));
356
357    return (gIODisplayWrangler->
358            getConnectFlagsForDisplayMode(connect, mode, flags));
359}
360
361/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
362
363static IOPMPowerState ourPowerStates[kIODisplayWranglerNumPowerStates] = {
364            // version,
365            //   capabilityFlags, outputPowerCharacter, inputPowerRequirement,
366            { 1, 0,                                      0, 0,           0,0,0,0,0,0,0,0 },
367            { 1, 0,                                      0, IOPMPowerOn, 0,0,0,0,0,0,0,0 },
368            { 1, 0,                                      0, IOPMPowerOn, 0,0,0,0,0,0,0,0 },
369            { 1, IOPMDeviceUsable | kIOPMPreventIdleSleep, 0, IOPMPowerOn, 0,0,0,0,0,0,0,0 },
370            { 1, IOPMDeviceUsable | kIOPMPreventIdleSleep, 0, IOPMPowerOn, 0,0,0,0,0,0,0,0 }
371            // staticPower, unbudgetedPower, powerToAttain, timeToAttain, settleUpTime,
372            // timeToLower, settleDownTime, powerDomainBudget
373        };
374
375
376/*
377    This is the Power Management policy-maker for the displays.  It senses when
378    the display is idle and lowers power accordingly.  It raises power back up
379    when the display becomes un-idle.
380
381    It senses idleness with a combination of an idle timer and the "activityTickle"
382    method call.  "activityTickle" is called by objects which sense keyboard activity,
383    mouse activity, or other button activity (display contrast, display brightness,
384    PCMCIA eject).  The method sets a "displayInUse" flag.  When the timer expires,
385    this flag is checked.  If it is on, the display is judged "in use".  The flag is
386    cleared and the timer is restarted.
387
388    If the flag is off when the timer expires, then there has been no user activity
389    since the last timer expiration, and the display is judged idle and its power is
390    lowered.
391
392    The period of the timer is a function of the current value of Power Management
393    aggressiveness.  As that factor varies from 1 to 999, the timer period varies
394    from 1004 seconds to 6 seconds.  Above 1000, the system is in a very aggressive
395    power management condition, and the timer period is 5 seconds.  (In this case,
396    the display dims between five and ten seconds after the last user activity).
397
398    This driver calls the drivers for each display and has them move their display
399    between various power states. When the display is idle, its power is dropped
400    state by state until it is in the lowest state.  When it becomes un-idle it is
401    powered back up to the state where it was last being used.
402
403    In times of very high power management aggressiveness, the display will not be
404    operated above the lowest power state which is marked "usable".
405
406    When Power Management is turned off (aggressiveness = 0), the display is never
407    judged idle and never dimmed.
408
409    We register with Power Management only so that we can be informed of changes in
410    the Power Management aggressiveness factor.  We don't really have a device with
411    power states so we implement the absolute minimum. The display drivers themselves
412    are part of the Power Management hierarchy under their respective frame buffers.
413*/
414
415/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
416// initForPM
417//
418
419void IODisplayWrangler::initForPM(void )
420{
421    // initialize superclass variables
422    PMinit();
423
424    // attach into the power management hierarchy
425    joinPMtree( this );
426
427    // register ourselves with policy-maker (us)
428    registerPowerDriver( this, ourPowerStates, kIODisplayWranglerNumPowerStates );
429    makeUsable();
430
431    // HID system is waiting for this
432    registerService();
433}
434
435unsigned long IODisplayWrangler::initialPowerStateForDomainState( IOPMPowerFlags domainState )
436{
437    if (domainState & IOPMPowerOn)
438        return (kIODisplayWranglerMaxPowerState);
439    else
440        return (0);
441}
442
443/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
444// setAggressiveness
445//
446// We are informed by our power domain parent of a new level of "power management
447// aggressiveness" which we use as a factor in our judgement of when we are idle.
448// This change implies a change in our idle timer period, so restart that timer.
449// timer.
450
451IOReturn IODisplayWrangler::setAggressiveness( unsigned long type, unsigned long newLevel )
452{
453    switch (type)
454    {
455
456      case kIOFBCaptureAggressiveness:
457
458        if (fDimCaptured && !newLevel)
459            activityTickle(0,0);
460
461        fDimCaptured = (0 != newLevel);
462        setProperty("DimCaptured", fDimCaptured);
463
464        /* fall thru */
465
466      case kPMMinutesToDim:
467        // minutes to dim received
468        if (kPMMinutesToDim == type)
469        {
470            // Display will always dim at least kMinDimTime seconds before
471            // display sleep kicks in.
472            fMinutesToDim = newLevel;
473			clock_interval_to_absolutetime_interval(fMinutesToDim * 60, kSecondScale, &fOffInterval[0]);
474
475			uint32_t annoyedInterval = fMinutesToDim * 60 * 2;
476			if (annoyedInterval > kMaxAnnoyanceInterval) annoyedInterval = kMaxAnnoyanceInterval;
477			if (annoyedInterval < (fMinutesToDim * 60))  annoyedInterval = (fMinutesToDim * 60);
478			clock_interval_to_absolutetime_interval(annoyedInterval, kSecondScale, &fOffInterval[1]);
479			AbsoluteTime_to_scalar(&fSettingsChanged) = mach_absolute_time();
480
481			DEBG2("W", " fMinutesToDim %ld, annoyed %d\n", newLevel, annoyedInterval);
482        }
483
484        newLevel = fDimCaptured ? 0 : fMinutesToDim;
485        if (newLevel == 0)
486        {
487            // pm turned off while idle?
488            if (getPowerState() < kIODisplayWranglerMaxPowerState)
489            {
490                // yes, bring displays up again
491//                activityTickle(0,0);
492                changePowerStateToPriv( kIODisplayWranglerMaxPowerState );
493            }
494        }
495        setIdleTimerPeriod(newLevel * 30);
496        break;
497
498      default:
499        break;
500    }
501    super::setAggressiveness(type, newLevel);
502    return (IOPMNoErr);
503}
504
505
506/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
507// setPowerState
508//
509// The vanilla policy-maker in the superclass is changing our power state.
510// If it's down, inform the displays to lower one state, too.  If it's up,
511// the idle displays are made usable.
512
513IOReturn IODisplayWrangler::setPowerState( unsigned long powerStateOrdinal, IOService * whatDevice )
514{
515    fPendingPowerState = powerStateOrdinal;
516
517    DEBG2("W", " (%ld), pwr %d open %d\n",
518                powerStateOrdinal, gIOGraphicsSystemPower, fOpen);
519
520    if (powerStateOrdinal == 0)
521    {
522        // system is going to sleep
523        // keep displays off on wake till UI brings them up
524        changePowerStateToPriv(0);
525        return (IOPMNoErr);
526    }
527
528    if (!gIOGraphicsSystemPower || !fOpen)
529        return (IOPMNoErr);
530    else if (powerStateOrdinal < getPowerState())
531    {
532        // HI is idle, drop power
533        if (kIODisplayWranglerMaxPowerState == getPowerState())
534        {
535			clock_interval_to_deadline(kAnnoyanceWithin, kSecondScale, &fAnnoyanceUntil);
536        }
537
538		if (powerStateOrdinal < 3) fAnnoyed = false;
539
540        IOFramebuffer::updateDisplaysPowerState();
541    }
542    else if (powerStateOrdinal == kIODisplayWranglerMaxPowerState)
543    {
544        // there is activity, raise power
545        IOFramebuffer::updateDisplaysPowerState();
546
547		start_PM_idle_timer();
548    }
549    return (IOPMNoErr);
550}
551
552unsigned long IODisplayWrangler::getDisplaysPowerState(void)
553{
554    unsigned long state = gIODisplayWrangler
555                                ? gIODisplayWrangler->fPendingPowerState
556                                : kIODisplayWranglerMaxPowerState;
557    return (state);
558}
559
560/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
561// nextIdleTimeout
562//
563// Virtual member function of IOService
564// overridden here to provide custom power-down behavior for dimming displays.
565// - Transition from 4->3 (to dim on built-in LCDs)
566// - Transition from 3->2 (to full display sleep on all machines)
567//   will occur at exactly N minutes from last user activity, where N
568//   is the value chosen by the user and set via setAggressiveness().
569
570SInt32 IODisplayWrangler::nextIdleTimeout(
571    AbsoluteTime currentTime,
572    AbsoluteTime lastActivity,
573    unsigned int powerState)
574{
575	AbsoluteTime deadline;
576	uint64_t delayNS = 0;
577	SInt32   delaySecs = 0;
578
579    if (!fOpen)
580    {
581        enum { kWindowServerStartTime = 24 * 60 * 60 };
582        return (kWindowServerStartTime);
583    }
584
585	if (CMP_ABSOLUTETIME(&fSettingsChanged, &lastActivity) > 0) lastActivity = fSettingsChanged;
586
587    switch (fPendingPowerState)
588    {
589        case 4:
590            // The system is currently in its 'on' state
591        case 3:
592            // The system is currently in its 'dim' state
593            // The transition into the next 'display sleep' state must occur
594            // fMinutesToDim after last UI activity
595			deadline = lastActivity;
596			ADD_ABSOLUTETIME(&deadline, &fOffInterval[fAnnoyed]);
597			if (4 == fPendingPowerState) SUB_ABSOLUTETIME(&deadline, &fDimInterval);
598			if (CMP_ABSOLUTETIME(&deadline, &currentTime) > 0)
599			{
600				SUB_ABSOLUTETIME(&deadline, &currentTime);
601				absolutetime_to_nanoseconds(deadline, &delayNS);
602				delaySecs = delayNS / kSecondScale;
603			}
604            break;
605
606        case 2:
607        case 1:
608            delaySecs = fMinutesToDim * 30;
609            break;
610        case 0:
611        default:
612            // error
613            delaySecs = 60;
614            break;
615    }
616
617	DEBG2("W", " %ld, %d, annoyed %d, now %lld, last %lld\n",
618				fPendingPowerState, (int) delaySecs, fAnnoyed,
619				AbsoluteTime_to_scalar(&currentTime),
620				AbsoluteTime_to_scalar(&lastActivity));
621
622    if (!delaySecs) delaySecs = 1;
623
624    return (delaySecs);
625}
626
627/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
628// activityTickle
629//
630// This is called by the HID system and calls the superclass in turn.
631
632bool IODisplayWrangler::activityTickle( unsigned long x, unsigned long y )
633{
634    AbsoluteTime now;
635
636    if (!fOpen)
637        return (true);
638
639    AbsoluteTime_to_scalar(&now) = mach_absolute_time();
640    if (AbsoluteTime_to_scalar(&fIdleUntil))
641    {
642        if (CMP_ABSOLUTETIME(&now, &fIdleUntil) < 0)
643            return (true);
644        AbsoluteTime_to_scalar(&fIdleUntil) = 0;
645    }
646
647    // Record if this was an annoyance.
648    if (AbsoluteTime_to_scalar(&fAnnoyanceUntil))
649	{
650		DEBG2("W", " now %lld, annoyed until %lld\n",
651				AbsoluteTime_to_scalar(&now),
652				AbsoluteTime_to_scalar(&fAnnoyanceUntil));
653
654        if (CMP_ABSOLUTETIME(&now, &fAnnoyanceUntil) < 0)
655            fAnnoyed = true;
656        AbsoluteTime_to_scalar(&fAnnoyanceUntil) = 0;
657	}
658
659    if (super::activityTickle(kIOPMSuperclassPolicy1,
660                kIODisplayWranglerMaxPowerState) )
661    {
662        return (true);
663    }
664
665    getPMRootDomain()->wakeFromDoze();
666
667    return (false);
668}
669
670OSObject * IODisplayWrangler::copyProperty( const char * aKey ) const
671{
672    if (!strcmp(aKey, kIOGraphicsPrefsKey))
673        return (IOFramebuffer::copyPreferences());
674    return (super::copyProperty(aKey));
675}
676
677IOReturn IODisplayWrangler::setProperties( OSObject * properties )
678{
679    OSDictionary * dict;
680    OSDictionary * prefs;
681    OSObject *     obj;
682    OSNumber *     num;
683    uint32_t       idleFor = 0;
684    enum { kIODisplayRequestDefaultIdleFor = 1000,
685            kIODisplayRequestMaxIdleFor    = 15000 };
686
687    if (!(dict = OSDynamicCast(OSDictionary, properties)))
688        return (kIOReturnBadArgument);
689
690    if ((prefs = OSDynamicCast(OSDictionary,
691                              dict->getObject(kIOGraphicsPrefsKey))))
692    {
693        return (IOFramebuffer::setPreferences(this, prefs));
694    }
695
696    obj = dict->getObject(kIORequestIdleKey);
697    if (kOSBooleanTrue == obj)
698    {
699        idleFor = kIODisplayRequestDefaultIdleFor;
700    }
701    else if (kOSBooleanFalse == obj)
702    {
703        AbsoluteTime_to_scalar(&fIdleUntil) = 0;
704        activityTickle(0, 0);
705    }
706    else if ((num = OSDynamicCast(OSNumber, obj)))
707    {
708        idleFor = num->unsigned32BitValue();
709        if (idleFor > kIODisplayRequestMaxIdleFor)
710            idleFor = kIODisplayRequestMaxIdleFor;
711    }
712
713    if (idleFor)
714    {
715		DEBG1("W", " idleFor(%d)\n", idleFor);
716
717        clock_interval_to_deadline(idleFor, kMillisecondScale, &fIdleUntil);
718        if (getPowerState() > 1)
719            changePowerStateToPriv(1);
720        return (kIOReturnSuccess);
721    }
722
723    return (kIOReturnSuccess);
724}
725