]> git.saurik.com Git - apple/xnu.git/blob - iokit/Families/IOGraphics/IODisplay.cpp
8bcf2fdd9d7aa483163a582d7c004f7e31bf54fc
[apple/xnu.git] / iokit / Families / IOGraphics / IODisplay.cpp
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 * Copyright (c) 1997-1998 Apple Computer, Inc.
24 *
25 *
26 * HISTORY
27 *
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
32 */
33
34 #include <libkern/OSAtomic.h>
35 #include <IOKit/graphics/IODisplay.h>
36 #include <IOKit/IOLib.h>
37 #include <IOKit/assert.h>
38
39 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
40
41 const OSSymbol * gIODisplayParametersKey;
42 const OSSymbol * gIODisplayGUIDKey;
43
44 const OSSymbol * gIODisplayValueKey;
45 const OSSymbol * gIODisplayMinValueKey;
46 const OSSymbol * gIODisplayMaxValueKey;
47
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;
58
59 const OSSymbol * gIODisplayParametersCommitKey;
60 const OSSymbol * gIODisplayParametersDefaultKey;
61
62 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
63
64 #undef super
65 #define super IOService
66
67 OSDefineMetaClass( IODisplay, IOService )
68 OSDefineAbstractStructors( IODisplay, IOService )
69
70 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
71
72 void IODisplay::initialize( void )
73 {
74 gIODisplayParametersKey = OSSymbol::withCStringNoCopy(
75 kIODisplayParametersKey );
76 gIODisplayGUIDKey = OSSymbol::withCStringNoCopy(
77 kIODisplayGUIDKey );
78 gIODisplayValueKey = OSSymbol::withCStringNoCopy(
79 kIODisplayValueKey );
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 );
104
105 gIODisplayParametersCommitKey = OSSymbol::withCStringNoCopy(
106 kIODisplayParametersCommitKey );
107 gIODisplayParametersDefaultKey = OSSymbol::withCStringNoCopy(
108 kIODisplayParametersDefaultKey );
109 }
110
111 IOService * IODisplay::probe( IOService * provider,
112 SInt32 * score )
113 {
114 connection = OSDynamicCast(IODisplayConnect, provider);
115
116 return( this );
117 }
118
119 IODisplayConnect * IODisplay::getConnection( void )
120 {
121 return( connection );
122 }
123
124
125 IOReturn IODisplay::getGammaTableByIndex(
126 UInt32 * /* channelCount */, UInt32 * /* dataCount */,
127 UInt32 * /* dataWidth */, void ** /* data */ )
128 {
129 return( kIOReturnUnsupported);
130 }
131
132
133 bool IODisplay::start( IOService * provider )
134 {
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
141 registerService();
142 }
143 return true;
144 }
145 return false;
146 }
147
148 IOReturn IODisplay::setProperties( OSObject * properties )
149 {
150 IOService * handler;
151 OSDictionary * dict;
152 OSDictionary * dict2;
153
154 dict = OSDynamicCast( OSDictionary, properties);
155 if( !dict)
156 return( kIOReturnUnsupported );
157
158 dict2 = OSDynamicCast( OSDictionary, dict->getObject(gIODisplayParametersKey));
159 if( dict2)
160 dict = dict2;
161
162 handler = getClientWithCategory(gIODisplayParametersKey);
163 if( !handler)
164 return( kIOReturnUnsupported );
165
166 return( handler->setProperties( dict ) );
167 }
168
169 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
170
171 /*
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).
176
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.
179 */
180
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}
188 };
189
190
191 void IODisplay::initForPM ( IOService * provider )
192 {
193 UInt32 capabilities = 0;
194 unsigned long number_of_power_states;
195 UInt32 currentSyncs = 0;
196 IOReturn err;
197
198 displayPMVars->connectIndex = connection->getConnection(); // find out our index in the nub
199
200 // what are the sync-controlling capabilities of the framebuffer?
201 err = connection->getAttributeForConnection( displayPMVars->connectIndex,
202 kConnectionSyncEnable, &capabilities );
203
204 // find out current state of sync lines
205 err = connection->getAttributeForConnection( displayPMVars->connectIndex,
206 kConnectionSyncFlags, &currentSyncs );
207
208 displayPMVars->currentSyncs = currentSyncs;
209 displayPMVars->powerControllable = true;
210
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);
220 }
221 else {
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;
228 }
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;
238 }
239 }
240
241 PMinit(); // initialize superclass variables
242 provider->joinPMtree(this); // attach into the power management hierarchy
243
244 registerPowerDriver(this,ourPowerStates,number_of_power_states); // register ourselves with policy-maker (us)
245
246 }
247
248
249 //*********************************************************************************
250 // registerPowerDriver
251 //
252 // We intercept this call to our superclass just to snoop early on
253 // the number of power states.
254 //*********************************************************************************
255
256 IOReturn IODisplay::registerPowerDriver ( IOService* x, IOPMPowerState*y, unsigned long numberOfStates )
257 {
258 displayPMVars->max_display_state = numberOfStates - 1;
259 return super::registerPowerDriver(x,y,numberOfStates);
260 }
261
262
263 //*********************************************************************************
264 // setAggressiveness
265 //
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 //*********************************************************************************
270
271 IOReturn IODisplay::setAggressiveness ( unsigned long type, unsigned long newLevel )
272 {
273 unsigned long i;
274
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 ) {
279 break;
280 }
281 }
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
285 }
286 }
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
292 }
293 }
294 }
295 }
296 super::setAggressiveness(type, newLevel);
297 return IOPMNoErr;
298 }
299
300
301 // **********************************************************************************
302 // dropOneLevel
303 //
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 )
309 {
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
315 }
316 else {
317 changePowerStateToPriv(0); // this may rescind previous request for domain power
318 }
319 }
320 }
321 }
322
323
324 //*********************************************************************************
325 // makeDisplayUsable
326 //
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
330 // initialized.
331 //*********************************************************************************
332 void IODisplay::makeDisplayUsable ( void )
333 {
334 if ( initialized && displayPMVars->powerControllable) {
335 displayPMVars->displayIdle = false;
336 if ( pm_vars != NULL ) {
337 changePowerStateToPriv(displayPMVars->max_display_state);
338 }
339 }
340 }
341
342
343 // **********************************************************************************
344 // setPowerState
345 //
346 // Called by the superclass to change the display power state.
347 // **********************************************************************************
348 IOReturn IODisplay::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice )
349 {
350 UInt32 flags;
351 if( initialized) {
352 flags =(displayPMVars->syncControls[powerStateOrdinal])<<8;
353 flags |= displayPMVars->syncMask;
354 displayPMVars->currentSyncs = displayPMVars->syncControls[powerStateOrdinal];
355 connection->setAttributeForConnection( displayPMVars->connectIndex, kConnectionSyncEnable, flags );
356 }
357 return IOPMAckImplied;
358 }
359
360
361 // **********************************************************************************
362 // maxCapabilityForDomainState
363 //
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 )
369 {
370 if ( domainState & IOPMPowerOn ) {
371 return pm_vars->theNumberOfPowerStates-1;
372 }
373 else {
374 return 0;
375 }
376 }
377
378
379 // **********************************************************************************
380 // initialPowerStateForDomainState
381 //
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 )
388 {
389 long unsigned i;
390
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) ) {
395 break;
396 }
397 }
398 return i;
399 }
400 else {
401 return 0; // domain is down, so display is off
402 }
403 }
404
405
406 // **********************************************************************************
407 // powerStateForDomainState
408 //
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 )
415 {
416 long unsigned i;
417
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) ) {
422 break;
423 }
424 }
425 return i;
426 }
427 else {
428 return 0; // domain is down, so display is off
429 }
430 }
431
432
433
434 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
435
436 #undef super
437 #define super IODisplay
438
439 OSDefineMetaClassAndStructors(AppleSenseDisplay, IODisplay)
440
441
442 IOService * AppleSenseDisplay::probe( IOService * provider,
443 SInt32 * score )
444 {
445 IODisplayConnect * connect;
446 IOFramebuffer * framebuffer;
447 IOService * ret = 0;
448 UInt32 sense, extSense;
449 UInt32 senseType, displayType;
450
451 do {
452
453 if( 0 == super::probe( provider, score ))
454 continue;
455
456 connect = getConnection();
457 if( !connect)
458 continue;
459
460 framebuffer = connect->getFramebuffer();
461 assert( framebuffer );
462
463 if( kIOReturnSuccess != framebuffer->getAttributeForConnection(
464 connect->getConnection(),
465 kConnectionSupportsAppleSense, NULL ))
466 continue;
467
468 ret = this;
469
470 if( kIOReturnSuccess != framebuffer->getAppleSense(
471 connect->getConnection(),
472 &senseType, &sense, &extSense, &displayType ))
473 continue;
474 sense = ((sense & 0xff) << 8) | (extSense & 0xff);
475 setProperty( kDisplayProductID, sense, 32);
476 setProperty( kDisplayVendorID, kDisplayVendorIDUnknown, 32);
477 setProperty( "AppleDisplayType", displayType, 32);
478
479 } while( false);
480
481 return( ret );
482 }
483
484 IOReturn AppleSenseDisplay::getConnectFlagsForDisplayMode(
485 IODisplayModeID mode, UInt32 * flags )
486 {
487 IOFramebuffer * framebuffer;
488 IODisplayConnect * connect;
489
490 connect = getConnection();
491 framebuffer = connect->getFramebuffer();
492
493 return( framebuffer->connectFlags(
494 connect->getConnection(),
495 mode, flags ));
496 }
497
498 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
499
500
501 #undef super
502 #define super IODisplay
503
504 OSDefineMetaClassAndStructors(AppleNoSenseDisplay, IODisplay)
505
506
507 IOReturn AppleNoSenseDisplay::getConnectFlagsForDisplayMode(
508 IODisplayModeID /* mode */, UInt32 * flags)
509 {
510 *flags = kDisplayModeValidFlag | kDisplayModeSafeFlag;
511
512 setProperty( kDisplayProductID, kDisplayProductIDGeneric, 32);
513 setProperty( kDisplayVendorID, kDisplayVendorIDUnknown, 32);
514
515 return( kIOReturnSuccess );
516 }
517
518