]>
Commit | Line | Data |
---|---|---|
1c79356b A |
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, ¤tSyncs ); | |
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 |