As I’ve mentioned before, ubuntu 9.04 Jaunty has been running fine on my ASUS UL20A laptop. Except the screen brightness buttons, Fn-F5 (down) and Fn-F6 (up).
Fn-F5 was setting brightness to the darkest value while Fn-F6 to the second darkest one. I’ve managed to create a crufty workaround, detailed below. It’s all about hacking the configuration of acpid (the ACPI daemon).
Set Brightness Directly
There is a special file called /proc/acpi/video/VGA/LCDD/brightness which lists the available and the actual brightness values. Brightest is shown below.
szg@OG3:/proc/acpi/video/VGA/LCDD$ cat brightness
levels: 10 16 22 28 34 40 46 52 58 64 70 76 82 88
current: 88
Setting brightness is done by writing a number into this file, the example shows darkest possible.
echo 10 > /proc/acpi/video/VGA/LCDD/brightness
Explore What Events the Brightness Keys Generate
Start the program called “acpi_listen”, which will print power-management related events when they happen.
When hitting Fn-F5 (Brightness down):
video LCDD 00000087 00000000
hotkey ATKD 00000020 000000fc
When hitting Fn-F6 (Brightness up):
video LCDD 00000086 00000000
hotkey ATKD 00000011 00000106
So each hotkey generates two events. Now let’s see how these events are handled. (Hard to see, as by now the screen is very dark. Bugger.)
Configure How acpid Handles Events
The configuration of “acpid” is in the “/etc/acpi/events” directory. Each file here handles one event type, line “event=regexp” defines the event, where the regexp shall match something like above, while line “action=command” the callback.
Fn-F5 (down) video LCDD 00000087 00000000 is handled by file “video_brightnessdown”:
event=video.* 00000087
action=/etc/acpi/video_brightnessdown.sh
Fn-F5 (down) hotkey ATKD 00000020 00000000fc is handled by “asus-brightness-down”:
event=hotkey (ATKD|HOTK) 0000002[0123456789abcdef]
action=/etc/acpi/asus-brn-down.sh
Fn-F6 (up) video LCDD 00000086 00000000 is handled by file “video_brightnessup”:
event=video.* 00000086
action=/etc/acpi/video_brightnessup.sh
Fn-F6 (up) hotkey ATKD 00000011 0000000106 is handled by “asus-brightness-up”:
event=hotkey (ATKD|HOTK) 0000001[0123456789abcdef]
action=/etc/acpi/asus-brn-up.sh
As you can see the callback scripts are in “/etc/acpi”.
Test the acpid Callback Scripts
Running all four callback scipts directly from the command line revealed they don’t work at all. Absolutely no effect on brightness. That’s why I now ignore their contents completely.
The test revealed something else as well: the broken function of both hotkeys comes from outside of this acpid-config mechanism. Probably the kernel. Which I won’t try to fix, I’ll just create a workaround.
The Fix
I linked the fixed callbacks to the second event for each hotkey, “hotkey ATKD 00000020″ (down) and “hotkey ATKD 00000011″ (up). Configured by “asus-brightness-down” and “asus-brightness-up”, respectively. I’ve removed the other two config files (video_brightnessdown/up) completely, which were handling the first event for each hotkey.
The new callback script for brightness down reads the actual value from a new config file (/etc/acpi/brightness), decrements it by 6, and stores it to the config file AND the “/proc/acpi/video/VGA/LCDD/brightness” file as well.
#!/bin/bash
if [ ! -f /etc/acpi/brightness ]; then echo 88 > /etc/acpi/brightness; fi
BRIGHTNESS=`cat /etc/acpi/brightness`
if [ $BRIGHTNESS -gt 10 ]; then let BRIGHTNESS-=6; fi
echo $BRIGHTNESS > /etc/acpi/brightness
echo $BRIGHTNESS > /proc/acpi/video/VGA/LCDD/brightness
The new brighness up script is similar, just increments the value by 6.
#!/bin/bash
if [ ! -f /etc/acpi/brightness ]; then echo 88 > /etc/acpi/brightness; fi
BRIGHTNESS=`cat /etc/acpi/brightness`
if [ $BRIGHTNESS -gt 10 ]; then let BRIGHTNESS+=6; fi
echo $BRIGHTNESS > /etc/acpi/brightness
echo $BRIGHTNESS > /proc/acpi/video/VGA/LCDD/brightness
The final touch: the callback script for AC/battery events (power.sh) also writes the config file to guarantee we always start changing the brightness from the actual value.
...
for x in /proc/acpi/ac_adapter/*; do
grep -q off-line $x/state
if [ $? = 0 ] && [ x$1 != xstop ]; then
for SCRIPT in /etc/acpi/battery.d/*.sh; do
. $SCRIPT
done
echo 52 > /etc/acpi/brightness
echo 52 > /proc/acpi/video/VGA/LCDD/brightness
else
for SCRIPT in /etc/acpi/ac.d/*.sh; do
. $SCRIPT
done
echo 88 > /etc/acpi/brightness
echo 88 > /proc/acpi/video/VGA/LCDD/brightness
fi
done
Now, when hitting the brightness hotkeys, the screen switches to the darkest setting for a moment, but then it works. Perfect. Nearly.