2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
22 #include <IOKit/IOWorkLoop.h>
23 #include <IOKit/IOCommandQueue.h>
24 #include <IOKit/IOTimerEventSource.h>
25 #include <IOKit/IOPlatformExpert.h>
26 #include <IOKit/pwr_mgt/RootDomain.h>
27 #include <IOKit/pwr_mgt/IOPM.h>
28 #include <IOKit/IOMessage.h>
29 #include "RootDomainUserClient.h"
32 extern void kprintf(const char *, ...);
35 extern const IORegistryPlane
* gIOPowerPlane
;
37 void PMreceiveCmd ( OSObject
*, void *, void *, void *, void * );
38 bool rootHasPMU( OSObject
* us
, void *, IOService
* yourDevice
);
41 #define number_of_power_states 3
46 #define ON_POWER IOPMPowerOn
47 #define SLEEP_POWER IOPMAuxPowerOn
49 static IOPMPowerState ourPowerStates
[number_of_power_states
] = {
50 {1,0,0,0,0,0,0,0,0,0,0,0},
51 {1,0,0,SLEEP_POWER
,0,0,0,0,0,0,0,0},
52 {1,IOPMPowerOn
,IOPMPowerOn
,ON_POWER
,0,0,0,0,0,0,0,0},
55 static IOPMrootDomain
* gRootDomain
;
57 #define super IOService
58 OSDefineMetaClassAndStructors(IOPMrootDomain
,IOService
)
62 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
= 0)
64 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
67 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
69 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
75 // **********************************************************************************
78 // We don't do much here. The real initialization occurs when the platform
79 // expert informs us we are the root.
80 // **********************************************************************************
81 bool IOPMrootDomain::start ( IOService
* nub
)
89 sleepIsSupported
= false;
92 // systemBooting = false; // temporary work-around for 2589847
93 ignoringClamshell
= false;
95 pm_vars
->PMworkloop
= IOWorkLoop::workLoop(); // make the workloop
96 pm_vars
->commandQueue
= IOCommandQueue::commandQueue(this, PMreceiveCmd
); // make a command queue
97 if (! pm_vars
->commandQueue
||
98 ( pm_vars
->PMworkloop
->addEventSource( pm_vars
->commandQueue
) != kIOReturnSuccess
) ) {
102 patriarch
= new IORootParent
; // create our parent
104 patriarch
->attach(this);
105 patriarch
->start(this);
106 patriarch
->youAreRoot();
107 patriarch
->wakeSystem();
108 patriarch
->addPowerChild(this);
110 registerPowerDriver(this,ourPowerStates
,number_of_power_states
);
112 // Clamp power on. We will revisit this decision when the login window is displayed
113 // and we receive preferences via SetAggressiveness.
114 changePowerStateToPriv(ON_STATE
); // clamp power on
115 powerOverrideOnPriv();
117 registerService(); // let clients find us
123 //*********************************************************************************
126 // Power Managment is informing us that we are the root power domain.
127 // We know we are not the root however, since we have just instantiated a parent
128 // for ourselves and made it the root. We override this method so it will have
130 //*********************************************************************************
131 IOReturn
IOPMrootDomain::youAreRoot ( void )
137 // **********************************************************************************
140 // We have received a command from ourselves on the command queue.
141 // If it is to send a recently-received aggressiveness factor, do so.
142 // Otherwise, it's something the superclass enqueued.
143 // **********************************************************************************
144 void IOPMrootDomain::command_received ( void * command
, void * x
, void * y
, void * z
)
146 switch ( (int)command
) {
147 case kPMbroadcastAggressiveness
:
148 if ( (int)x
== kPMMinutesToSleep
) {
149 idlePeriod
= (int)y
*60;
150 if ( allowSleep
&& sleepIsSupported
) {
151 setIdleTimerPeriod(idlePeriod
); // set new timeout
156 super::command_received(command
,x
,y
,z
);
162 //*********************************************************************************
165 // Some aggressiveness factor has changed. We put this change on our
166 // command queue so that we can broadcast it to the hierarchy while on
167 // the Power Mangement workloop thread. This enables objects in the
168 // hierarchy to successfully alter their idle timers, which are all on the
170 //*********************************************************************************
172 IOReturn
IOPMrootDomain::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
174 systemBooting
= false; // when the finder launches, this method gets called -- system booting is done.
176 pm_vars
->commandQueue
->enqueueCommand(true, (void *)kPMbroadcastAggressiveness
, (void *) type
, (void *) newLevel
);
177 super::setAggressiveness(type
,newLevel
);
179 return kIOReturnSuccess
;
183 // **********************************************************************************
186 // **********************************************************************************
187 IOReturn
IOPMrootDomain::sleepSystem ( void )
189 kprintf("sleep demand received\n");
190 if ( !systemBooting
&& allowSleep
&& sleepIsSupported
) {
191 patriarch
->sleepSystem();
193 return kIOReturnSuccess
;
197 // **********************************************************************************
200 // This overrides powerChangeDone in IOService.
201 // If we just finished switching to state zero, call the platform expert to
203 // Then later, when we awake, the kernel returns here and we wake the system.
204 // **********************************************************************************
205 void IOPMrootDomain::powerChangeDone ( unsigned long powerStateOrdinal
)
207 if ( powerStateOrdinal
== SLEEP_STATE
) {
208 pm_vars
->thePlatform
->sleepKernel();
209 activityTickle(kIOPMSubclassPolicy
); // reset idle sleep
210 systemWake(); // tell the tree we're waking
211 patriarch
->wakeSystem(); // make sure we have power
212 changePowerStateToPriv(ON_STATE
); // and wake
217 // **********************************************************************************
220 // **********************************************************************************
221 IOReturn
IOPMrootDomain::newUserClient( task_t owningTask
, void * /* security_id */, UInt32 type
, IOUserClient
** handler
)
223 IOReturn err
= kIOReturnSuccess
;
224 RootDomainUserClient
* client
;
226 client
= RootDomainUserClient::withTask(owningTask
);
228 if( !client
|| (false == client
->attach( this )) ||
229 (false == client
->start( this )) ) {
231 client
->detach( this );
235 err
= kIOReturnNoMemory
;
241 //*********************************************************************************
242 // receivePowerNotification
244 // The power controller is notifying us of a hardware-related power management
245 // event that we must handle. This is a result of an 'environment' interrupt from
246 // the power mgt micro.
247 //*********************************************************************************
249 IOReturn
IOPMrootDomain::receivePowerNotification (UInt32 msg
)
251 if (msg
& kIOPMSleepNow
) {
252 (void) sleepSystem ();
255 if (msg
& kIOPMPowerButton
) {
256 (void) sleepSystem ();
259 if (msg
& kIOPMPowerEmergency
) {
260 (void) sleepSystem ();
263 if (msg
& kIOPMClamshellClosed
) {
264 if ( ! ignoringClamshell
) {
265 (void) sleepSystem ();
269 if (msg
& kIOPMIgnoreClamshell
) {
270 ignoringClamshell
= true;
273 if (msg
& kIOPMAllowSleep
) {
274 if ( sleepIsSupported
) {
275 setIdleTimerPeriod(idlePeriod
);
278 changePowerStateTo (0);
281 // if the case is open on some machines, we must now
282 // allow the machine to be put to sleep or to idle sleep
284 if (msg
& kIOPMPreventSleep
) {
285 if ( sleepIsSupported
) {
286 setIdleTimerPeriod(0);
289 changePowerStateTo (number_of_power_states
-1);
296 //*********************************************************************************
299 //*********************************************************************************
301 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
303 platformSleepSupport
= flags
;
304 if ( flags
& kRootDomainSleepSupported
) {
305 sleepIsSupported
= true;
306 setProperty("IOSleepSupported","");
310 sleepIsSupported
= false;
311 removeProperty("IOSleepSupported");
316 //*********************************************************************************
319 //*********************************************************************************
321 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
323 return( platformSleepSupport
);
327 //*********************************************************************************
330 // We override the superclass implementation so we can send a different message
331 // type to the client or application being notified.
332 //*********************************************************************************
334 bool IOPMrootDomain::tellChangeDown ( unsigned long stateNum
)
336 if ( stateNum
== SLEEP_STATE
) {
337 return super::tellClientsWithResponse(kIOMessageSystemWillSleep
);
339 return super::tellChangeDown(stateNum
);
343 //*********************************************************************************
346 // We override the superclass implementation so we can send a different message
347 // type to the client or application being notified.
348 //*********************************************************************************
350 bool IOPMrootDomain::askChangeDown (unsigned long stateNum
)
352 if ( stateNum
== SLEEP_STATE
) {
353 return super::tellClientsWithResponse(kIOMessageCanSystemSleep
);
355 return super::askChangeDown(stateNum
);
359 //*********************************************************************************
362 // Notify registered applications and kernel clients that we are not
365 // We override the superclass implementation so we can send a different message
366 // type to the client or application being notified.
367 //*********************************************************************************
369 void IOPMrootDomain::tellNoChangeDown ( unsigned long )
371 return tellClients(kIOMessageSystemWillNotSleep
);
375 //*********************************************************************************
378 // Notify registered applications and kernel clients that we are raising power.
380 // We override the superclass implementation so we can send a different message
381 // type to the client or application being notified.
382 //*********************************************************************************
384 void IOPMrootDomain::tellChangeUp ( unsigned long )
386 return tellClients(kIOMessageSystemHasPoweredOn
);
390 // **********************************************************************************
393 // This is called by the HID system and calls the superclass in turn.
394 // **********************************************************************************
396 bool IOPMrootDomain::activityTickle ( unsigned long, unsigned long x
=0 )
398 return super::activityTickle (kIOPMSuperclassPolicy1
,ON_STATE
);
404 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
407 #define super IOService
409 OSDefineMetaClassAndStructors(IORootParent
, IOService
)
411 #define number_of_patriarch_power_states 3
413 static IOPMPowerState patriarchPowerStates
[number_of_patriarch_power_states
] = {
414 {1,0,0,0,0,0,0,0,0,0,0,0}, // off
415 {1,0,SLEEP_POWER
,0,0,0,0,0,0,0,0,0}, // sleep
416 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0} // running
419 #define PATRIARCH_OFF 0
420 #define PATRIARCH_SLEEP 1
421 #define PATRIARCH_ON 2
424 bool IORootParent::start ( IOService
* nub
)
428 registerPowerDriver(this,patriarchPowerStates
,number_of_patriarch_power_states
);
429 powerOverrideOnPriv();
434 void IORootParent::shutDownSystem ( void )
436 changePowerStateToPriv(PATRIARCH_OFF
);
440 void IORootParent::sleepSystem ( void )
442 changePowerStateToPriv(PATRIARCH_SLEEP
);
446 void IORootParent::wakeSystem ( void )
448 changePowerStateToPriv(PATRIARCH_ON
);