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 #include <IOKit/IOLib.h>
24 #include <IOKit/graphics/IODisplay.h>
25 #include <IOKit/ndrvsupport/IOMacOSVideo.h>
27 #include <Drivers/hidsystem/drvAppleADBDevices/AppleADBButtons.h>
29 #define kNumber_of_power_states 4
30 #define kNumber_of_power_levels 32
32 #define kScreenBit 0x01
34 #define kPowerOff 0x00
35 #define kDisplayOn kScreenBit | kPowerOn
36 #define kDisplayOff kScreenBit | kPowerOff
38 class AppleG3SeriesDisplay
: public AppleSenseDisplay
40 OSDeclareDefaultStructors(AppleG3SeriesDisplay
)
44 int current_user_brightness
; // 0-31. The brightness level last selected via the brightness buttons.
45 int current_level
; // 0-31. The current brightness level
46 IOService
* PMUdriver
; // points to PMU driver
47 int * rawTable
; // points to table of raw brightess levels
49 // the constants used to talk with the pmu:
51 kPMUpower1Read
= 0x19, // more power status (DBLite)
52 kPMUReadBrightness
= 0x49, // read the brightness value
53 kPMUpower1Cntl
= 0x11, // more power control (DBLite)
54 kPMUSetBrightness
= 0x41 // set screen brightness
57 // We need this to callPlatformFunction when sending to sendMiscCommand
58 typedef struct SendMiscCommandParameterBlock
{
64 } SendMiscCommandParameterBlock
;
65 typedef SendMiscCommandParameterBlock
*SendMiscCommandParameterBlockPtr
;
67 // A simpler way to interface with the pmu SendMiscCommand
68 IOReturn
localSendMiscCommand(int command
, IOByteCount sLength
, UInt8
*sBuffer
, IOByteCount
*rLength
, UInt8
*rBuffer
);
71 IOService
* probe ( IOService
*, SInt32
* );
72 virtual void initForPM ( IOService
* );
73 virtual IOReturn
setPowerState ( unsigned long, IOService
* );
74 virtual unsigned long maxCapabilityForDomainState ( IOPMPowerFlags
);
75 virtual unsigned long initialPowerStateForDomainState ( IOPMPowerFlags
);
76 virtual unsigned long powerStateForDomainState ( IOPMPowerFlags
);
77 virtual void ourButtonHandler ( unsigned int );
78 virtual void setBrightness ( long );
81 void upButtonHandler(AppleG3SeriesDisplay
*);
82 void downButtonHandler(AppleG3SeriesDisplay
*);
86 The actual display panel has 128 power levels. Copying the MacOS, we only implement 32 of them.
87 We further divide the 32 into four IOKit power states which we export to our superclass.
89 In the lowest state, the display is off. This state consists of only one of the 32 power levels, the lowest.
90 In the next state it is in the dimmest usable state. This state also consists of only one of the 32 levels, the second lowest.
91 The next state is also dim and consists of seven of the 32 levels.
92 The highest state consists of the highest 23 levels.
94 The display has no state or configuration or programming that would be saved/restored over power state changes,
95 and the driver does not register with the superclass as an interested driver.
97 This driver doesn't have much to do. It changes between the four power state brightnesses on command
98 from the superclass, and it raises and lowers the display brightness by one of the 32 brightness levels
99 when it receives a brightness-button interrupt from the ADB stack.
101 The only smart thing it does is keep track of which of the 32 brightness levels the user has selected by button, and it
102 never exceeds that on command from the display device object. It only raises above that on an brightness-up-button
108 static IOPMPowerState ourPowerStates
[kNumber_of_power_states
] = {
109 {1,0,0,0,0,0,0,0,0,0,0,0},
110 {1,IOPMDeviceUsable
,0,IOPMPowerOn
,0,0,0,0,0,0,0,0},
111 {1,IOPMDeviceUsable
,0,IOPMPowerOn
,0,0,0,0,0,0,0,0},
112 {1,IOPMDeviceUsable
+IOPMMaxPerformance
,0,IOPMPowerOn
,0,0,0,0,0,0,0,0}
115 static int max_brightness_level
[kNumber_of_power_states
] = {0,1,8,31};
117 static int HooperTable
[ ] = {127,71,69,67,65,63,61,59,
118 58,56,54,52,50,48,46,44,
119 42,40,38,37,35,33,31,29,
120 27,25,23,21,19,18,16,14 };
122 bool ourNotificationHandler( OSObject
*, void *, IOService
* );
124 #define super AppleSenseDisplay
126 OSDefineMetaClassAndStructors(AppleG3SeriesDisplay
, AppleSenseDisplay
)
129 // **********************************************************************************
132 // **********************************************************************************
133 IOService
* AppleG3SeriesDisplay::probe ( IOService
* provider
, SInt32
* score
)
135 IOFramebuffer
* framebuffer
;
141 if ( 0 == super::probe( provider
, score
) ) {
145 framebuffer
= (IOFramebuffer
*)getConnection()->getFramebuffer(); // point to our framebuffer
146 ourIndex
= getConnection()->getConnection(); // get our connection index on this framebuffer
148 if ( kIOReturnSuccess
!= framebuffer
->getAppleSense(ourIndex
,NULL
,NULL
,NULL
,&displayType
) ) {
152 if ( !(displayType
== kPanelTFTConnect
) ) { // does it have a panel attached?
155 ret
= this; // yes, we will control the panel
162 // **********************************************************************************
163 // localSendMiscCommand
165 // **********************************************************************************
166 IOReturn
AppleG3SeriesDisplay::localSendMiscCommand(int command
, IOByteCount sLength
, UInt8
*sBuffer
, IOByteCount
*rLength
, UInt8
*rBuffer
)
168 IOReturn returnValue
= kIOReturnError
;
170 // The poupose of this method is to free us from the pain to create a parameter block each time
171 // we wish to talk to the pmu:
172 SendMiscCommandParameterBlock prmBlock
= {command
, sLength
, sBuffer
, rLength
, rBuffer
};
174 IOLog("AppleG3SeriesDisplay::localSendMiscCommand 0x%02x %d 0x%08lx 0x%08lx 0x%08lx\n",
175 command
, sLength
, sBuffer
, rLength
, rBuffer
);
177 if (PMUdriver
!= NULL
) {
178 IOLog("AppleG3SeriesDisplay::localSendMiscCommand calling PMUdriver->callPlatformFunction\n");
179 returnValue
= PMUdriver
->callPlatformFunction("sendMiscCommand", true, (void*)&prmBlock
, NULL
, NULL
, NULL
);
182 // If we are here we do not have a dreive to talk to:
183 IOLog("AppleG3SeriesDisplay::localSendMiscCommand end 0x%08lx\n", returnValue
);
188 // **********************************************************************************
191 // This method overrides the one in IODisplay.h to do PowerBook-only
192 // power management of the display.
193 // **********************************************************************************
194 void AppleG3SeriesDisplay::initForPM ( IOService
* provider
)
198 UInt8 PMUreceiveBuffer
[10]; // (I think 1 is enough, but it scares me)
199 IOByteCount unused
= sizeof(PMUreceiveBuffer
);
201 displayPMVars
->powerControllable
= true;
203 PMinit(); // initialize superclass variables
205 PMUdriver
= waitForService(serviceMatching("ApplePMU"));
207 rawTable
= HooperTable
;
209 localSendMiscCommand(kPMUpower1Read
,0, NULL
, &unused
,PMUreceiveBuffer
);
211 if ( PMUreceiveBuffer
[0] & kScreenBit
) { // is the screen currently on?
212 unused
= sizeof(PMUreceiveBuffer
);
213 localSendMiscCommand(kPMUReadBrightness
,0, NULL
, &unused
,PMUreceiveBuffer
); // yes, figure out the brightness
214 current_user_brightness
= kNumber_of_power_levels
- 1; // ( in case the for-loop doesn't break)
215 current_level
= kNumber_of_power_levels
- 1;
217 for ( i
= 0; i
< kNumber_of_power_levels
; i
++ ) {
218 if ( PMUreceiveBuffer
[0] >= rawTable
[i
] ) {
219 current_user_brightness
= i
;
226 current_user_brightness
= 0;
230 addNotification( gIOPublishNotification
,serviceMatching("AppleADBButtons"), // look for the button driver
231 (IOServiceNotificationHandler
)ourNotificationHandler
, this, 0 );
233 provider
->joinPMtree(this); // attach into the power management hierarchy
234 registerPowerDriver(this,ourPowerStates
,kNumber_of_power_states
); // register with policy-maker (us)
238 // **********************************************************************************
239 // ourNotificationHandler
241 // The ADB button driver has appeared. Tell it we are interested in the
242 // brightness-up button and the brightness-down button.
243 // **********************************************************************************
244 bool ourNotificationHandler( OSObject
* us
, void * ref
, IOService
* yourDevice
)
246 if ( yourDevice
!= NULL
) {
247 ((AppleADBButtons
*)yourDevice
)->registerForButton(kBrightness_up
,(IOService
*)us
,(button_handler
)upButtonHandler
,true);
248 ((AppleADBButtons
*)yourDevice
)->registerForButton(kBrightness_down
,(IOService
*)us
,(button_handler
)downButtonHandler
,true);
254 // **********************************************************************************
257 // All power state changes require a call to the PMU driver, which
258 // blocks the thread till the command completes.
259 // **********************************************************************************
260 IOReturn
AppleG3SeriesDisplay::setPowerState ( unsigned long powerStateOrdinal
, IOService
* whatDevice
)
262 UInt8 displayOn
= kDisplayOn
;
263 UInt8 displayOff
= kDisplayOff
;
266 if ( powerStateOrdinal
< kNumber_of_power_states
) {
267 if ( powerStateOrdinal
> pm_vars
->myCurrentState
) { // raising power
268 if ( pm_vars
->myCurrentState
== 0 ) { // is it currently off?
269 IOByteCount unused
= 0;
270 localSendMiscCommand(kPMUpower1Cntl
,1, &displayOn
, &unused
,NULL
);
272 current_level
= max_brightness_level
[powerStateOrdinal
];
273 if ( current_user_brightness
< current_level
) {
274 current_level
= current_user_brightness
; // don't exceed what the user used to have it at
276 setBrightness(current_level
);
277 // If we are still higher than we need to be, request a lower state
278 for ( i
= 0; i
< kNumber_of_power_states
; i
++ ) { // figure out what state we should be in
279 if ( current_level
<= max_brightness_level
[i
] ) {
283 if ( pm_vars
->myCurrentState
> i
) {
284 changePowerStateToPriv(i
);
288 if ( powerStateOrdinal
< pm_vars
->myCurrentState
) { // lowering power
289 if (powerStateOrdinal
== 0 ) { // going all the way off?
290 IOByteCount unused
= 0;
291 localSendMiscCommand(kPMUpower1Cntl
,1, &displayOff
, &unused
,NULL
); // yes
292 current_level
= max_brightness_level
[powerStateOrdinal
];
295 if ( current_level
> max_brightness_level
[powerStateOrdinal
] ) { // no
296 current_level
= max_brightness_level
[powerStateOrdinal
];
297 setBrightness(current_level
);
302 return IOPMAckImplied
;
306 // **********************************************************************************
307 // maxCapabilityForDomainState
309 // This simple device needs only power. If the power domain is supplying
310 // power, the display can go to its highest state. If there is no power
311 // it can only be in its lowest state, which is off.
312 // **********************************************************************************
313 unsigned long AppleG3SeriesDisplay::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
315 if ( domainState
& IOPMPowerOn
) {
316 return kNumber_of_power_states
-1;
322 // **********************************************************************************
323 // initialPowerStateForDomainState
325 // The power domain may be changing state. If power is on in the new
326 // state, that will not affect our state at all. If domain power is off,
327 // we can attain only our lowest state, which is off.
328 // **********************************************************************************
329 unsigned long AppleG3SeriesDisplay::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
333 if ( domainState
& IOPMPowerOn
) { // domain has power
334 for ( i
= 0; i
< kNumber_of_power_states
; i
++ ) { // find power state that has our current
335 if ( current_level
<= max_brightness_level
[i
] ) { // brightness level
341 return 0; // domain is down, so display is off
345 // **********************************************************************************
346 // powerStateForDomainState
348 // The power domain may be changing state. If power is on in the new
349 // state, that will not affect our state at all. If domain power is off,
350 // we can attain only our lowest state, which is off.
351 // **********************************************************************************
352 unsigned long AppleG3SeriesDisplay::powerStateForDomainState ( IOPMPowerFlags domainState
)
356 if ( domainState
& IOPMPowerOn
) { // domain has power
357 for ( i
= 0; i
< kNumber_of_power_states
; i
++ ) { // find power state that has our current
358 if ( current_level
<= max_brightness_level
[i
] ) { // brightness level
363 return 0; // domain is down, so display is off
367 // **********************************************************************************
370 // The display-brightness-up button just went down.
371 // We are running on a new thread made by the ADB Button driver
372 // **********************************************************************************
373 void upButtonHandler(AppleG3SeriesDisplay
* us
)
375 ((AppleG3SeriesDisplay
*)us
)->ourButtonHandler(kBrightness_up
);
379 // **********************************************************************************
382 // The display-brightness-down button just went down.
383 // We are running on a new thread made by the ADB Button driver
384 // **********************************************************************************
385 void downButtonHandler(AppleG3SeriesDisplay
* us
)
387 ((AppleG3SeriesDisplay
*)us
)->ourButtonHandler(kBrightness_down
);
391 // **********************************************************************************
394 // Alter the backlight brightness up or down by one increment.
395 // This involves a call to the PMU driver, which will block the thread.
396 // **********************************************************************************
397 void AppleG3SeriesDisplay::ourButtonHandler ( unsigned int keycode
)
398 { // If we are idle, ignore the button.
399 // The display will be made usable
400 if ( ! displayPMVars
->displayIdle
) { // by the DisplayWrangler
402 case kBrightness_up
: // The brightness-up button has just been pressed
403 // We make sure the brightness is not above the maximum
404 // brightness level of our current power state. If it
405 // is too high, we ask the device to raise power.
406 if (current_level
< max_brightness_level
[pm_vars
->myCurrentState
] ) {
408 current_user_brightness
= current_level
;
409 setBrightness(current_level
);
412 if ( pm_vars
->myCurrentState
< (kNumber_of_power_states
-1) ) {
413 current_user_brightness
++; // increment user's desire
414 if ( changePowerStateToPriv(pm_vars
->myCurrentState
+ 1) != IOPMNoErr
) { // request higher power
415 current_user_brightness
--; // can't
421 case kBrightness_down
: // The brightness-down button has just been pressed
422 // We lower the brightness, and if that takes us into a
423 // lower power state, we tell our parent about it.
424 if ( pm_vars
->myCurrentState
> 0 ) { // don't lower if in lowest (off) state
425 if ( current_level
> 0 ) {
427 current_user_brightness
= current_level
;
428 setBrightness(current_level
);
429 if (current_level
<= max_brightness_level
[pm_vars
->myCurrentState
- 1] ) { // if this takes us into the next lower state
430 changePowerStateToPriv(pm_vars
->myCurrentState
- 1); // request lower power
440 // **********************************************************************************
443 // Instruct PMU to set the display brightness.
444 // This will block the thread while the command completes.
445 // **********************************************************************************
446 void AppleG3SeriesDisplay::setBrightness ( long brightness
)
448 IOByteCount unused
= 0;
449 UInt8 setBrightnessBuffer
;
451 setBrightnessBuffer
= (UInt8
)rawTable
[brightness
];
452 localSendMiscCommand(kPMUSetBrightness
,1, &setBrightnessBuffer
, &unused
,NULL
);