|
|
1.1 root 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) 1999 Apple Computer, Inc.
24: *
25: *
26: * HISTORY
27: *
28: * sdouglas 18 Mar 99 - first checked in.
29: */
30:
31:
32: #include <IOKit/assert.h>
33: #include <IOKit/IOLib.h>
34: #include <IOKit/IOPlatformExpert.h>
35:
36: #include "IODisplayWrangler.h"
37:
38: #define CGS true
39:
40: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
41:
42: // tiddly nub
43:
44: #undef super
45: #define super IOService
46:
47: OSDefineMetaClassAndStructors(IODisplayConnect, IOService)
48:
49: bool IODisplayConnect::initWithConnection( IOIndex _connection )
50: {
51: char name[ 12 ];
52:
53: if( !super::init())
54: return( false);
55:
56: connection = _connection;
57:
58: sprintf( name, "display%ld", connection);
59:
60: setName( name);
61:
62: return( true);
63: }
64:
65: IOFramebuffer * IODisplayConnect::getFramebuffer( void )
66: {
67: return( (IOFramebuffer *) getProvider());
68: }
69:
70: IOIndex IODisplayConnect::getConnection( void )
71: {
72: return( connection);
73: }
74:
75: IOReturn IODisplayConnect::getAttributeForConnection( IOIndex connectIndex, IOSelect selector, UInt32 * value )
76: {
77: return ((IOFramebuffer *) getProvider())->getAttributeForConnection( connectIndex, selector, value );
78: }
79:
80: IOReturn IODisplayConnect::setAttributeForConnection( IOIndex connectIndex, IOSelect selector, UInt32 info )
81: {
82: return ((IOFramebuffer *) getProvider())->setAttributeForConnection( connectIndex, selector, info );
83: }
84:
85:
86: //*********************************************************************************
87: // joinPMtree
88: //
89: // The policy-maker in the display driver calls here when initializing.
90: // We attach it into the power management hierarchy as a child of our
91: // frame buffer.
92: //*********************************************************************************
93: void IODisplayConnect::joinPMtree ( IOService * driver )
94: {
95: getProvider()->addChild(driver);
96: }
97:
98:
99: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
100:
101: #define super IOService
102: OSDefineMetaClassAndStructors(IODisplayWrangler, IOService);
103:
104: IODisplayWrangler * gIODisplayWrangler;
105:
106: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
107:
108: bool IODisplayWrangler::start( IOService * provider )
109: {
110: OSObject * notify;
111:
112: if( !super::start( provider))
113: return( false);
114:
115: assert( gIODisplayWrangler == 0 );
116: gIODisplayWrangler = this;
117:
118: fMatchingLock = IOLockAlloc();
119: fFramebuffers = OSSet::withCapacity( 1 );
120: fDisplays = OSSet::withCapacity( 1 );
121:
122: assert( fMatchingLock && fFramebuffers && fDisplays );
123:
124: notify = addNotification( gIOPublishNotification,
125: serviceMatching("IODisplay"), _displayHandler,
126: this, fDisplays );
127: assert( notify );
128:
129: notify = addNotification( gIOPublishNotification,
130: serviceMatching("IODisplayConnect"), _displayConnectHandler,
131: this, 0, 50000 );
132: assert( notify );
133:
134: return( true );
135: }
136:
137: bool IODisplayWrangler::_displayHandler( void * target, void * ref,
138: IOService * newService )
139: {
140:
141: return( ((IODisplayWrangler *)target)->displayHandler( (OSSet *) ref,
142: (IODisplay *) newService ));
143: }
144:
145: bool IODisplayWrangler::_displayConnectHandler( void * target, void * ref,
146: IOService * newService )
147: {
148: return( ((IODisplayWrangler *)target)->displayConnectHandler( ref,
149: (IODisplayConnect *) newService ));
150: }
151:
152: bool IODisplayWrangler::displayHandler( OSSet * set,
153: IODisplay * newDisplay )
154: {
155: assert( OSDynamicCast( IODisplay, newDisplay ));
156:
157: IOTakeLock( fMatchingLock );
158:
159: set->setObject( newDisplay );
160:
161: IOUnlock( fMatchingLock );
162:
163: return( true );
164: }
165:
166: bool IODisplayWrangler::displayConnectHandler( void * /* ref */,
167: IODisplayConnect * connect )
168: {
169: SInt32 score = 50000;
170: OSIterator * iter;
171: IODisplay * display;
172: bool found = false;
173:
174: assert( OSDynamicCast( IODisplayConnect, connect ));
175:
176: IOTakeLock( fMatchingLock );
177:
178: iter = OSCollectionIterator::withCollection( fDisplays );
179: if( iter) {
180: while( !found && (display = (IODisplay *) iter->getNextObject())) {
181: if( display->getConnection())
182: continue;
183:
184: do {
185: if( !display->attach( connect ))
186: continue;
187: found = ((display->probe( connect, &score ))
188: && (display->start( connect )));
189: if( !found)
190: display->detach( connect );
191: } while( false);
192: }
193: iter->release();
194: }
195:
196: IOUnlock( fMatchingLock );
197:
198: return( true);
199: }
200:
201: IOReturn IODisplayWrangler::clientStart( IOFramebuffer * fb )
202: {
203: IOReturn err = kIOReturnSuccess;
204:
205: // IOTakeLock( fFBLock );
206:
207: if( gIODisplayWrangler &&
208: gIODisplayWrangler->fFramebuffers->setObject( fb )) {
209:
210: // framebuffer not yet done
211:
212: err = fb->open();
213: if( kIOReturnSuccess == err) {
214: gIODisplayWrangler->initForPM(); // initialize power managment
215: gIODisplayWrangler->setAggressiveness ( kPMMinutesToDim, 30 ); // set default screen-dim timeout
216: gIODisplayWrangler->makeDisplayConnects( fb );
217: gIODisplayWrangler->findStartupMode( fb );
218: } else
219: gIODisplayWrangler->fFramebuffers->removeObject( fb );
220: }
221:
222: // IOUnlock( fFBLock );
223:
224: return( err );
225: }
226:
227: bool IODisplayWrangler::makeDisplayConnects( IOFramebuffer * fb )
228: {
229: IODisplayConnect * connect;
230: IOItemCount i;
231:
232: for( i = 0; i < fb->getConnectionCount(); i++) {
233:
234: connect = new IODisplayConnect;
235: if( 0 == connect)
236: continue;
237:
238: if( (connect->initWithConnection( i ))
239: && (connect->attach( fb ))) {
240:
241: connect->registerService( kIOServiceSynchronous );
242: }
243: connect->release();
244: }
245:
246: return( true );
247: }
248:
249: IODisplayConnect * IODisplayWrangler::getDisplayConnect(
250: IOFramebuffer * fb, IOIndex connect )
251: {
252: OSIterator * iter;
253: OSObject * next;
254: IODisplayConnect * connection = 0;
255:
256: iter = fb->getClientIterator();
257: if( iter) {
258: while( (next = iter->getNextObject())) {
259: connection = OSDynamicCast( IODisplayConnect, next);
260: if( connection && (0 == (connect--)))
261: break;
262: }
263: iter->release();
264: }
265: return( connection );
266: }
267:
268:
269: IOReturn IODisplayWrangler::getConnectFlagsForDisplayMode(
270: IODisplayConnect * connect,
271: IODisplayModeID mode, UInt32 * flags )
272: {
273: IOReturn err = kIOReturnUnsupported;
274: IODisplay * display;
275:
276: display = OSDynamicCast( IODisplay, connect->getClient());
277: if( display)
278: err = display->getConnectFlagsForDisplayMode( mode, flags );
279: else {
280: kprintf("%s: no display\n", connect->getFramebuffer()->getName());
281: err = connect->getFramebuffer()->connectFlags(
282: connect->getConnection(), mode, flags );
283: }
284:
285: return( err );
286: }
287:
288: IOReturn IODisplayWrangler::getFlagsForDisplayMode(
289: IOFramebuffer * fb,
290: IODisplayModeID mode, UInt32 * flags )
291: {
292: IODisplayConnect * connect;
293:
294: // should look at all connections
295: connect = gIODisplayWrangler->getDisplayConnect( fb, 0 );
296: if( !connect) {
297: kprintf("%s: no display connect\n", fb->getName());
298: return( kIOReturnUnsupported );
299: }
300:
301: return( gIODisplayWrangler->
302: getConnectFlagsForDisplayMode( connect, mode, flags ));
303: }
304:
305: IOReturn IODisplayWrangler::getDefaultMode( IOFramebuffer * fb,
306: IODisplayModeID * mode, IOIndex * depth )
307: {
308: UInt32 thisFlags, bestFlags = 0;
309: IODisplayModeID thisMode, bestMode = 0;
310: IOIndex bestDepth;
311: UInt32 i;
312: IOReturn err;
313: IODisplayModeInformation info;
314: char arg[ 64 ];
315: const char * param;
316: UInt32 lookWidth, lookHeight, lookRefresh, lookDepth;
317: static const char bitsToIndex[] = { 0, 0, 1, 1, 2 };
318: UInt32 numModes;
319: IODisplayModeID * allModes;
320: bool foundForced;
321:
322:
323: numModes = fb->getDisplayModeCount();
324: allModes = IONew( IODisplayModeID, numModes );
325:
326: if( NULL == allModes)
327: return( kIOReturnNoMemory);
328: err = fb->getDisplayModes( allModes );
329: if( err) // leak
330: return( err );
331:
332: if( PE_parse_boot_arg("dm", arg)) {
333:
334: param = arg;
335: lookWidth = strtol( param, (char **) ¶m, 0);
336: param++;
337: lookHeight = strtol( param, (char **) ¶m, 0);
338: param++;
339: lookRefresh = strtol( param, (char **) ¶m, 0);
340: param++;
341: lookDepth = strtol( param, (char **) ¶m, 0);
342: if( lookDepth == 15)
343: lookDepth = 16;
344: if( lookDepth > 32)
345: lookDepth = 32;
346:
347: kprintf("%s: Looking %dx%d@%d,%d\n", fb->getName(), lookWidth, lookHeight,
348: lookRefresh, lookDepth );
349:
350: } else {
351: param = 0;
352: lookWidth = 1024;
353: lookHeight = 768;
354: lookRefresh = 75;
355: lookDepth = 16;
356: }
357:
358: bestDepth = bitsToIndex[ lookDepth / 8 ];
359:
360: for( i = 0; i < numModes; i++) {
361:
362: thisMode = allModes[ i ];
363: if( getFlagsForDisplayMode( fb, thisMode, &thisFlags))
364: continue;
365:
366: if( CGS) {
367: // make sure it does 16/32 && requested mode
368: err = fb->getInformationForDisplayMode( thisMode, &info);
369: if( err)
370: continue;
371: if( 0 == info.maxDepthIndex)
372: continue;
373: #if 0
374: kprintf("%d x %d @ %d = %x\n", info.nominalWidth, info.nominalHeight,
375: info.refreshRate >> 16, thisFlags);
376: #endif
377: }
378:
379: if( 0 == (thisFlags & kDisplayModeValidFlag))
380: continue;
381:
382: foundForced = (param
383: && (info.nominalWidth == lookWidth)
384: && (info.nominalHeight == lookHeight)
385: && (((info.refreshRate + 0x8000) >> 16) == lookRefresh) );
386:
387: if( foundForced
388: || (thisFlags & kDisplayModeDefaultFlag)
389: || (((bestFlags & kDisplayModeDefaultFlag) == 0)
390: && (thisFlags & kDisplayModeSafeFlag)) ) {
391:
392: bestMode = thisMode;
393: bestFlags = thisFlags;
394:
395: bestDepth = bitsToIndex[ lookDepth / 8 ];
396: if( bestDepth > info.maxDepthIndex)
397: bestDepth = info.maxDepthIndex;
398:
399: if( foundForced)
400: break;
401: }
402: }
403:
404: IODelete( allModes, IODisplayModeID, numModes );
405:
406: if( bestMode) {
407: *mode = bestMode;
408: *depth = bestDepth;
409: return( kIOReturnSuccess);
410: } else
411: return( kIOReturnUnsupported);
412: }
413:
414: // Determine a startup mode given the framebuffer & displays
415:
416: IOReturn IODisplayWrangler::findStartupMode( IOFramebuffer * fb )
417: {
418: IODisplayModeID mode;
419: IOIndex depth;
420: IODisplayModeID startMode;
421: IOIndex startDepth;
422: UInt32 startFlags = 0;
423: IOReturn err;
424: IODisplayModeInformation info;
425:
426: fb->getCurrentDisplayMode( &mode, &depth);
427: err = fb->getStartupDisplayMode( &startMode, &startDepth );
428: if( err) {
429: startMode = mode;
430: startDepth = depth;
431: }
432:
433: do {
434: err = getFlagsForDisplayMode( fb, startMode, &startFlags );
435: if( err)
436: continue;
437: err = fb->getInformationForDisplayMode( startMode, &info);
438: if( err)
439: continue;
440:
441: if( CGS && (startDepth == 2))
442: startDepth = 1;
443:
444: if( CGS && (startDepth == 0) && (info.maxDepthIndex > 0))
445: startDepth = 1;
446:
447: if( (startDepth == 0)
448: || ((startFlags & kDisplayModeValidFlag)
449: != kDisplayModeValidFlag) ) {
450: // look for default
451: err = getDefaultMode( fb, &startMode, &startDepth );
452: }
453:
454: if( (startMode != mode) || (startDepth != depth))
455: fb->setDisplayMode( startMode, startDepth );
456:
457: } while( false );
458:
459: fb->setupForCurrentConfig();
460:
461: return( kIOReturnSuccess );
462: }
463:
464: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
465:
466: #define kNumber_of_power_states 4
467:
468: static IOPMPowerState ourPowerStates[kNumber_of_power_states] = {
469: {1,0,0,0,0,0,0,0,0,0,0,0},
470: {1,0,0,0,0,0,0,0,0,0,0,0},
471: {1,0,0,0,0,0,0,0,0,0,0,0},
472: {1,0,0,0,0,0,0,0,0,0,0,0}
473:
474: };
475:
476:
477: /*
478: This is the Power Management policy-maker for the displays. It senses when the display is idle
479: and lowers power accordingly. It raises power back up when the display becomes un-idle.
480:
481: It senses idleness with a combination of an idle timer and the "activityTickle" method call. "activityTickle"
482: is called by objects which sense keyboard activity, mouse activity, or other button activity (display contrast,
483: display brightness, PCMCIA eject). The method sets a "displayInUse" flag. When the timer expires,
484: this flag is checked. If it is on, the display is judged "in use". The flag is cleared and the timer is restarted.
485:
486: If the flag is off when the timer expires, then there has been no user activity since the last timer
487: expiration, and the display is judged idle and its power is lowered.
488:
489: The period of the timer is a function of the current value of Power Management aggressiveness. As that factor
490: varies from 1 to 999, the timer period varies from 1004 seconds to 6 seconds. Above 1000, the system is in
491: a very aggressive power management condition, and the timer period is 5 seconds. (In this case, the display dims
492: between five and ten seconds after the last user activity).
493:
494: This driver calls the drivers for each display and has them move their display between various power states.
495: When the display is idle, its power is dropped state by state until it is in the lowest state. When it becomes un-idle
496: it is powered back up to the state where it was last being used.
497:
498: In times of very high power management aggressiveness, the display will not be operated above the lowest power
499: state which is marked "usable".
500:
501: When Power Management is turned off (aggressiveness = 0), the display is never judged idle and never dimmed.
502:
503: We register with Power Management only so that we can be informed of changes in the Power Management
504: aggressiveness factor. We don't really have a device with power states so we implement the absolute minimum.
505: The display drivers themselves are part of the Power Management hierarchy under their respective frame buffers.
506:
507: */
508:
509:
510: // **********************************************************************************
511: // initForPM
512: //
513: // **********************************************************************************
514: void IODisplayWrangler::initForPM (void )
515: {
516:
517: PMinit(); // initialize superclass variables
518:
519: mins_to_dim = 0;
520: use_general_aggressiveness = false;
521:
522: pm_vars->thePlatform->PMRegisterDevice(this,this); // attach into the power management hierarchy
523:
524: registerControllingDriver(this,ourPowerStates,kNumber_of_power_states); // register ourselves with policy-maker (us)
525:
526: registerService(); // HID system is waiting for this
527:
528: }
529:
530:
531: //*********************************************************************************
532: // setAggressiveness
533: //
534: // We are informed by our power domain parent of a new level of "power management
535: // aggressiveness" which we use as a factor in our judgement of when we are idle.
536: // This change implies a change in our idle timer period, so restart that timer.
537: // timer.
538: //*********************************************************************************
539:
540: IOReturn IODisplayWrangler::setAggressiveness ( unsigned long type, unsigned long newLevel )
541: {
542: if ( type == kPMMinutesToDim ) { // minutes to dim received
543: if( newLevel == 0 ) {
544: if( pm_vars->myCurrentState < kNumber_of_power_states-1 ) { // pm turned off while idle?
545: makeDisplaysUsable(); // yes, bring displays up again
546: }
547: }
548: mins_to_dim = newLevel;
549: use_general_aggressiveness = false;
550: if ( pm_vars->aggressiveness < kIOPowerEmergencyLevel ) { // no, currently in emergency level?
551: setIdleTimerPeriod(newLevel*60); // no, set new timeout
552: }
553: }
554: if ( type == kPMGeneralAggressiveness ) { // general factor received
555: if ( newLevel >= kIOPowerEmergencyLevel ) { // emergency level?
556: setIdleTimerPeriod(5); // yes
557: }
558: else {
559: if ( pm_vars->aggressiveness >= kIOPowerEmergencyLevel ) { // no, coming out of emergency level?
560: if (use_general_aggressiveness ) { // yes, set new timer period
561: setIdleTimerPeriod(333-(newLevel/3));
562: }
563: else {
564: setIdleTimerPeriod(mins_to_dim*60);
565: }
566: }
567: else {
568: if (use_general_aggressiveness ) { // no, maybe set period
569: setIdleTimerPeriod(333-(newLevel/3));
570: }
571: }
572: }
573: }
574: super::setAggressiveness(type, newLevel);
575: return IOPMNoErr;
576: }
577:
578:
579: // **********************************************************************************
580: // activityTickle
581: //
582: // This is called by the HID system and calls the superclass in turn.
583: // **********************************************************************************
584:
585: bool IODisplayWrangler::activityTickle ( unsigned long, unsigned long )
586: {
587: return super::activityTickle (kIOPMSuperclassPolicy1,kNumber_of_power_states-1 );
588: }
589:
590:
591: // **********************************************************************************
592: // maxCapabilityForDomainState
593: //
594: // This psuedo-device needs is normally in its highest power state, except
595: // when it is idling down the displays. So always return the highest state.
596: // **********************************************************************************
597:
598: unsigned long IODisplayWrangler::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
599: {
600: return kNumber_of_power_states-1;
601: }
602:
603:
604: // **********************************************************************************
605: // powerStateForDomainState
606: //
607: // This psuedo-device needs is normally in its highest power state, except
608: // when it is idling down the displays. So always return the highest state.
609: // **********************************************************************************
610: unsigned long IODisplayWrangler::powerStateForDomainState ( IOPMPowerFlags domainState )
611: {
612: return kNumber_of_power_states-1;
613: }
614:
615:
616: // **********************************************************************************
617: // initialPowerStateForDomainState
618: //
619: // This psuedo-device needs is normally in its highest power state, except
620: // when it is idling down the displays. So always return the highest state.
621: // **********************************************************************************
622: unsigned long IODisplayWrangler::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
623: {
624: return kNumber_of_power_states-1;
625: }
626:
627:
628: // **********************************************************************************
629: // setPowerState
630: //
631: // The vanilla policy-maker in the superclass is changing our power state.
632: // If it's down, inform the displays to lower one state, too. If it's up,
633: // the idle displays are made usable.
634: // **********************************************************************************
635: IOReturn IODisplayWrangler::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice )
636: {
637: if( powerStateOrdinal < pm_vars->myCurrentState ) { // dropping power
638: idleDisplays();
639: }
640: if( powerStateOrdinal > pm_vars->myCurrentState ) { // raising power
641: makeDisplaysUsable();
642: }
643: return IOPMNoErr;
644: }
645:
646:
647: // **********************************************************************************
648: // makeDisplaysUsable
649: //
650: // **********************************************************************************
651: void IODisplayWrangler::makeDisplaysUsable ( void )
652: {
653: OSIterator * iter;
654: IODisplay * display;
655:
656: IOTakeLock( fMatchingLock );
657:
658: iter = OSCollectionIterator::withCollection( fDisplays );
659: if( iter ) {
660: while( (display = (IODisplay *) iter->getNextObject()) ) {
661: display->makeDisplayUsable();
662: }
663: iter->release();
664: }
665: IOUnlock( fMatchingLock );
666: }
667:
668:
669: // **********************************************************************************
670: // idleDisplays
671: //
672: // **********************************************************************************
673: void IODisplayWrangler::idleDisplays ( void )
674: {
675: OSIterator * iter;
676: IODisplay * display;
677:
678: IOTakeLock( fMatchingLock );
679:
680: iter = OSCollectionIterator::withCollection( fDisplays );
681: if( iter ) {
682: while( (display = (IODisplay *) iter->getNextObject()) ) {
683: display->dropOneLevel();
684: }
685: iter->release();
686: }
687: IOUnlock( fMatchingLock );
688: }
689:
690:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.