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@
23 * Copyright (c) 1997-1998 Apple Computer, Inc.
28 * sdouglas 22 Oct 97 - first checked in.
29 * sdouglas 18 May 98 - make loadable.
30 * sdouglas 23 Jul 98 - start IOKit
31 * sdouglas 08 Dec 98 - start cpp
34 #include <libkern/OSAtomic.h>
35 #include <IOKit/graphics/IODisplay.h>
36 #include <IOKit/IOLib.h>
37 #include <IOKit/assert.h>
39 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
41 const OSSymbol
* gIODisplayParametersKey
;
42 const OSSymbol
* gIODisplayGUIDKey
;
44 const OSSymbol
* gIODisplayValueKey
;
45 const OSSymbol
* gIODisplayMinValueKey
;
46 const OSSymbol
* gIODisplayMaxValueKey
;
48 const OSSymbol
* gIODisplayContrastKey
;
49 const OSSymbol
* gIODisplayBrightnessKey
;
50 const OSSymbol
* gIODisplayHorizontalPositionKey
;
51 const OSSymbol
* gIODisplayHorizontalSizeKey
;
52 const OSSymbol
* gIODisplayVerticalPositionKey
;
53 const OSSymbol
* gIODisplayVerticalSizeKey
;
54 const OSSymbol
* gIODisplayTrapezoidKey
;
55 const OSSymbol
* gIODisplayPincushionKey
;
56 const OSSymbol
* gIODisplayParallelogramKey
;
57 const OSSymbol
* gIODisplayRotationKey
;
59 const OSSymbol
* gIODisplayParametersCommitKey
;
60 const OSSymbol
* gIODisplayParametersDefaultKey
;
62 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
65 #define super IOService
67 OSDefineMetaClass( IODisplay
, IOService
)
68 OSDefineAbstractStructors( IODisplay
, IOService
)
70 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
72 void IODisplay::initialize( void )
74 gIODisplayParametersKey
= OSSymbol::withCStringNoCopy(
75 kIODisplayParametersKey
);
76 gIODisplayGUIDKey
= OSSymbol::withCStringNoCopy(
78 gIODisplayValueKey
= OSSymbol::withCStringNoCopy(
80 gIODisplayMinValueKey
= OSSymbol::withCStringNoCopy(
81 kIODisplayMinValueKey
);
82 gIODisplayMaxValueKey
= OSSymbol::withCStringNoCopy(
83 kIODisplayMaxValueKey
);
84 gIODisplayContrastKey
= OSSymbol::withCStringNoCopy(
85 kIODisplayContrastKey
);
86 gIODisplayBrightnessKey
= OSSymbol::withCStringNoCopy(
87 kIODisplayBrightnessKey
);
88 gIODisplayHorizontalPositionKey
= OSSymbol::withCStringNoCopy(
89 kIODisplayHorizontalPositionKey
);
90 gIODisplayHorizontalSizeKey
= OSSymbol::withCStringNoCopy(
91 kIODisplayHorizontalSizeKey
);
92 gIODisplayVerticalPositionKey
= OSSymbol::withCStringNoCopy(
93 kIODisplayVerticalPositionKey
);
94 gIODisplayVerticalSizeKey
= OSSymbol::withCStringNoCopy(
95 kIODisplayVerticalSizeKey
);
96 gIODisplayTrapezoidKey
= OSSymbol::withCStringNoCopy(
97 kIODisplayTrapezoidKey
);
98 gIODisplayPincushionKey
= OSSymbol::withCStringNoCopy(
99 kIODisplayPincushionKey
);
100 gIODisplayParallelogramKey
= OSSymbol::withCStringNoCopy(
101 kIODisplayParallelogramKey
);
102 gIODisplayRotationKey
= OSSymbol::withCStringNoCopy(
103 kIODisplayRotationKey
);
105 gIODisplayParametersCommitKey
= OSSymbol::withCStringNoCopy(
106 kIODisplayParametersCommitKey
);
107 gIODisplayParametersDefaultKey
= OSSymbol::withCStringNoCopy(
108 kIODisplayParametersDefaultKey
);
111 IOService
* IODisplay::probe( IOService
* provider
,
114 connection
= OSDynamicCast(IODisplayConnect
, provider
);
119 IODisplayConnect
* IODisplay::getConnection( void )
121 return( connection
);
125 IOReturn
IODisplay::getGammaTableByIndex(
126 UInt32
* /* channelCount */, UInt32
* /* dataCount */,
127 UInt32
* /* dataWidth */, void ** /* data */ )
129 return( kIOReturnUnsupported
);
133 bool IODisplay::start( IOService
* provider
)
135 if ( super::start(provider
) ) {
136 if ( connection
!= NULL
) {
137 displayPMVars
= (DisplayPMVars
*)IOMalloc(sizeof(DisplayPMVars
)); // make space for our variables
138 assert( displayPMVars
);
139 displayPMVars
->displayIdle
= false; // initialize some
140 initForPM(provider
); // initialize power management of the device
148 IOReturn
IODisplay::setProperties( OSObject
* properties
)
152 OSDictionary
* dict2
;
154 dict
= OSDynamicCast( OSDictionary
, properties
);
156 return( kIOReturnUnsupported
);
158 dict2
= OSDynamicCast( OSDictionary
, dict
->getObject(gIODisplayParametersKey
));
162 handler
= getClientWithCategory(gIODisplayParametersKey
);
164 return( kIOReturnUnsupported
);
166 return( handler
->setProperties( dict
) );
169 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
172 This is the power-controlling driver for a display. It also acts as an agent of the policy-maker for display power
173 which is the DisplayWrangler. The Display Wrangler calls here to lower power by one state when it senses
174 no user activity. It also calls here to make the display usable after it has been idled down, and it also calls
175 here to make the display barely usable if it senses a power emergency (e.g. low battery).
177 This driver assumes a video display, and it calls the framebuffer driver to control the sync signals. Non-video
178 display drivers (e.g. flat panels) subclass IODisplay and override this and other appropriate methods.
181 static IOPMPowerState ourPowerStates
[kIODisplayMaxPowerStates
] = {
182 {1,0,0,0,0,0,0,0,0,0,0,0},
183 // {1,0,0,IOPMPowerOn,0,0,0,0,0,0,0,0},
184 // {1,0,0,IOPMPowerOn,0,0,0,0,0,0,0,0},
185 {1,0,0,0,0,0,0,0,0,0,0,0},
186 {1,0,0,0,0,0,0,0,0,0,0,0},
187 {1,IOPMDeviceUsable
+IOPMMaxPerformance
,0,IOPMPowerOn
,0,0,0,0,0,0,0,0}
191 void IODisplay::initForPM ( IOService
* provider
)
193 UInt32 capabilities
= 0;
194 unsigned long number_of_power_states
;
195 UInt32 currentSyncs
= 0;
198 displayPMVars
->connectIndex
= connection
->getConnection(); // find out our index in the nub
200 // what are the sync-controlling capabilities of the framebuffer?
201 err
= connection
->getAttributeForConnection( displayPMVars
->connectIndex
,
202 kConnectionSyncEnable
, &capabilities
);
204 // find out current state of sync lines
205 err
= connection
->getAttributeForConnection( displayPMVars
->connectIndex
,
206 kConnectionSyncFlags
, ¤tSyncs
);
208 displayPMVars
->currentSyncs
= currentSyncs
;
209 displayPMVars
->powerControllable
= true;
211 if ( (capabilities
& kIOHSyncDisable
) &&
212 (capabilities
& kIOVSyncDisable
) &&
213 !(capabilities
& kIONoSeparateSyncControl
) ) { // four power states
214 number_of_power_states
= 4;
215 displayPMVars
->syncControls
[0] = 0 | kIOHSyncDisable
| kIOVSyncDisable
| kIOCSyncDisable
;
216 displayPMVars
->syncControls
[1] = 0 | kIOVSyncDisable
| kIOCSyncDisable
;
217 displayPMVars
->syncControls
[2] = 0 | kIOHSyncDisable
| kIOCSyncDisable
;
218 displayPMVars
->syncControls
[3] = 0;
219 displayPMVars
->syncMask
= capabilities
& (kIOHSyncDisable
| kIOVSyncDisable
| kIOCSyncDisable
);
222 if ( capabilities
& kIOCSyncDisable
) { // two power states
223 number_of_power_states
= 2;
224 ourPowerStates
[1].capabilityFlags
= ourPowerStates
[3].capabilityFlags
;
225 displayPMVars
->syncControls
[0] = 0 | kIOCSyncDisable
;
226 displayPMVars
->syncControls
[1] = 0;
227 displayPMVars
->syncMask
= 0 | kIOCSyncDisable
;
229 else { // two power states and not controllable
230 number_of_power_states
= 2;
231 ourPowerStates
[1].capabilityFlags
= ourPowerStates
[3].capabilityFlags
;
232 ourPowerStates
[0].capabilityFlags
|= IOPMNotAttainable
;
233 ourPowerStates
[1].capabilityFlags
|= IOPMNotAttainable
;
234 displayPMVars
->syncControls
[0] = displayPMVars
->currentSyncs
;
235 displayPMVars
->syncControls
[1] = displayPMVars
->currentSyncs
;
236 displayPMVars
->syncMask
= displayPMVars
->currentSyncs
;
237 displayPMVars
->powerControllable
= false;
241 PMinit(); // initialize superclass variables
242 provider
->joinPMtree(this); // attach into the power management hierarchy
244 registerPowerDriver(this,ourPowerStates
,number_of_power_states
); // register ourselves with policy-maker (us)
249 //*********************************************************************************
250 // registerPowerDriver
252 // We intercept this call to our superclass just to snoop early on
253 // the number of power states.
254 //*********************************************************************************
256 IOReturn
IODisplay::registerPowerDriver ( IOService
* x
, IOPMPowerState
*y
, unsigned long numberOfStates
)
258 displayPMVars
->max_display_state
= numberOfStates
- 1;
259 return super::registerPowerDriver(x
,y
,numberOfStates
);
263 //*********************************************************************************
266 // We are informed by our power domain parent of a new level of "power management
267 // aggressiveness". Our only interest is if it implies a power management
268 // emergency, in which case we keep the display brightness low.
269 //*********************************************************************************
271 IOReturn
IODisplay::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
275 if ( type
== kPMGeneralAggressiveness
) {
276 if ( newLevel
>= kIOPowerEmergencyLevel
) { // emergency level
277 for ( i
= 0; i
< pm_vars
->theNumberOfPowerStates
; i
++ ) { // find lowest usable state
278 if ( pm_vars
->thePowerStates
[i
].capabilityFlags
& IOPMDeviceUsable
) {
282 displayPMVars
->max_display_state
= i
;
283 if ( pm_vars
->myCurrentState
> i
) { // if we are currently above that,
284 changePowerStateToPriv(i
); // drop to emergency level
287 else { // not emergency level
288 if ( pm_vars
->aggressiveness
>= kIOPowerEmergencyLevel
) { // but it was emergency level
289 displayPMVars
->max_display_state
= pm_vars
->theNumberOfPowerStates
- 1;
290 if ( ! displayPMVars
->displayIdle
) {
291 changePowerStateToPriv(displayPMVars
->max_display_state
); // return to normal usable level
296 super::setAggressiveness(type
, newLevel
);
301 // **********************************************************************************
304 // Called by the display wrangler when it decides there hasn't been user
305 // activity for a while. We drop one power level. This can be called by the
306 // display wrangler before we have been completely initialized.
307 // **********************************************************************************
308 void IODisplay::dropOneLevel ( void )
310 if ( initialized
&& displayPMVars
->powerControllable
) {
311 displayPMVars
->displayIdle
= true;
312 if ( pm_vars
!= NULL
) {
313 if ( pm_vars
->myCurrentState
> 0 ) {
314 changePowerStateToPriv(pm_vars
->myCurrentState
- 1); // drop a level
317 changePowerStateToPriv(0); // this may rescind previous request for domain power
324 //*********************************************************************************
327 // The DisplayWrangler has sensed user activity after we have idled the
328 // display and wants us to make it usable again. We are running on its
329 // workloop thread. This can be called before we are completely
331 //*********************************************************************************
332 void IODisplay::makeDisplayUsable ( void )
334 if ( initialized
&& displayPMVars
->powerControllable
) {
335 displayPMVars
->displayIdle
= false;
336 if ( pm_vars
!= NULL
) {
337 changePowerStateToPriv(displayPMVars
->max_display_state
);
343 // **********************************************************************************
346 // Called by the superclass to change the display power state.
347 // **********************************************************************************
348 IOReturn
IODisplay::setPowerState ( unsigned long powerStateOrdinal
, IOService
* whatDevice
)
352 flags
=(displayPMVars
->syncControls
[powerStateOrdinal
])<<8;
353 flags
|= displayPMVars
->syncMask
;
354 displayPMVars
->currentSyncs
= displayPMVars
->syncControls
[powerStateOrdinal
];
355 connection
->setAttributeForConnection( displayPMVars
->connectIndex
, kConnectionSyncEnable
, flags
);
357 return IOPMAckImplied
;
361 // **********************************************************************************
362 // maxCapabilityForDomainState
364 // This simple device needs only power. If the power domain is supplying
365 // power, the display can go to its highest state. If there is no power
366 // it can only be in its lowest state, which is off.
367 // **********************************************************************************
368 unsigned long IODisplay::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
370 if ( domainState
& IOPMPowerOn
) {
371 return pm_vars
->theNumberOfPowerStates
-1;
379 // **********************************************************************************
380 // initialPowerStateForDomainState
382 // The power domain may be changing state. If power is on in the new
383 // state, that will not affect our state at all. In that case ask the ndrv
384 // what our current state is. If domain power is off, we can attain
385 // only our lowest state, which is off.
386 // **********************************************************************************
387 unsigned long IODisplay::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
391 if ( domainState
& IOPMPowerOn
) { // domain has power
392 for ( i
= pm_vars
->theNumberOfPowerStates
-1; i
> 0; i
-- ) { // compare to our table to find current power state
393 if ( (displayPMVars
->syncControls
[i
] & displayPMVars
->syncMask
)
394 == (displayPMVars
->currentSyncs
& displayPMVars
->syncMask
) ) {
401 return 0; // domain is down, so display is off
406 // **********************************************************************************
407 // powerStateForDomainState
409 // The power domain may be changing state. If power is on in the new
410 // state, that will not affect our state at all. In that case ask the ndrv
411 // what our current state is. If domain power is off, we can attain
412 // only our lowest state, which is off.
413 // **********************************************************************************
414 unsigned long IODisplay::powerStateForDomainState ( IOPMPowerFlags domainState
)
418 if ( domainState
& IOPMPowerOn
) { // domain has power
419 for ( i
= pm_vars
->theNumberOfPowerStates
-1; i
> 0; i
-- ) { // compare to our table to find current power state
420 if ( (displayPMVars
->syncControls
[i
] & displayPMVars
->syncMask
)
421 == (displayPMVars
->currentSyncs
& displayPMVars
->syncMask
) ) {
428 return 0; // domain is down, so display is off
434 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
437 #define super IODisplay
439 OSDefineMetaClassAndStructors(AppleSenseDisplay
, IODisplay
)
442 IOService
* AppleSenseDisplay::probe( IOService
* provider
,
445 IODisplayConnect
* connect
;
446 IOFramebuffer
* framebuffer
;
448 UInt32 sense
, extSense
;
449 UInt32 senseType
, displayType
;
453 if( 0 == super::probe( provider
, score
))
456 connect
= getConnection();
460 framebuffer
= connect
->getFramebuffer();
461 assert( framebuffer
);
463 if( kIOReturnSuccess
!= framebuffer
->getAttributeForConnection(
464 connect
->getConnection(),
465 kConnectionSupportsAppleSense
, NULL
))
470 if( kIOReturnSuccess
!= framebuffer
->getAppleSense(
471 connect
->getConnection(),
472 &senseType
, &sense
, &extSense
, &displayType
))
474 sense
= ((sense
& 0xff) << 8) | (extSense
& 0xff);
475 setProperty( kDisplayProductID
, sense
, 32);
476 setProperty( kDisplayVendorID
, kDisplayVendorIDUnknown
, 32);
477 setProperty( "AppleDisplayType", displayType
, 32);
484 IOReturn
AppleSenseDisplay::getConnectFlagsForDisplayMode(
485 IODisplayModeID mode
, UInt32
* flags
)
487 IOFramebuffer
* framebuffer
;
488 IODisplayConnect
* connect
;
490 connect
= getConnection();
491 framebuffer
= connect
->getFramebuffer();
493 return( framebuffer
->connectFlags(
494 connect
->getConnection(),
498 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
502 #define super IODisplay
504 OSDefineMetaClassAndStructors(AppleNoSenseDisplay
, IODisplay
)
507 IOReturn
AppleNoSenseDisplay::getConnectFlagsForDisplayMode(
508 IODisplayModeID
/* mode */, UInt32
* flags
)
510 *flags
= kDisplayModeValidFlag
| kDisplayModeSafeFlag
;
512 setProperty( kDisplayProductID
, kDisplayProductIDGeneric
, 32);
513 setProperty( kDisplayVendorID
, kDisplayVendorIDUnknown
, 32);
515 return( kIOReturnSuccess
);