This was annoying me. The KPowersave module could control my LCD's backlight, but the ACPI controls would not. Obviously, there is full hardware support, but the ACPI system isn't quite up to the task.

The ACPI scripts merely fake the keys when called, with a hard coded value. This, obviously, was not working.

So, I decided on a rather convoluted method. First, I ended up finding my actual brightness control device (there are several listed on my machine), by running the following as root (it will NOT work via sudo):

  %for n in /proc/acpi/video/**/LCD/brightness; do \
   echo "Trying $n..."; for fade in `seq 1 100`; do sleep \
   0.01s; echo -n "$fade" > $n; done; done

This will print the devices it finds, and attempt to set the LCD levels from 1 (nearly off) to 100 (full brightness). As different LCDs have different specifications, you can't just randomly assume a single number will work. I was being lazy, and although it didn't accept them all, it was still a neat effect.

I found that my LCD device was actually: /proc/acpi/video/VID1/LCD/brightness

Then, I made the world's ugliest parser to see what the available levels were, and to shift up, or down, according to the script. Since there are separate 'up' and 'down' scripts, I decided to be lazy. Have I mentioned yet how incredibly ugly this whole thing is? I wish there was a more bourne-ish portable way to deal with quasi-arrays.

Here's my new /etc/acpi/video_brightnessdown.sh:

#!/bin/sh
#Yeah, I got kind of lazy.  Arrays in Bourne SUCK.
DEVICE=/proc/acpi/video/VID1/LCD/brightness
#. /usr/share/acpi-support/key-constants
#acpi_fakekey $KEY_BRIGHTNESSDOWN
CURRENTLEVEL=`grep 'current:' $DEVICE | awk '{print $2}'`
if [ "x"$CURRENTLEVEL = "x0" ]; then
  CURRENTLEVEL=100
fi
SORTEDLEVELS=`grep 'levels:' $DEVICE | sed -e \
   s,levels:,,g -e 's,\s,\n,g' | sort -n | uniq | \
   grep -v '^$' | sed s,\n,\ ,g | xargs echo`
for levels in `echo $SORTEDLEVELS | sed 's,\n,\ ,g'`
do
    if [ $CURRENTLEVEL = $levels ]; then
      echo -n $LASTLEVEL > $DEVICE
      break
    fi
    LASTLEVEL=$levels
done
... and /etc/acpi/video_brightnessup.sh:

#!/bin/sh
#. /usr/share/acpi-support/key-constants
#acpi_fakekey $KEY_BRIGHTNESSUP
DEVICE=/proc/acpi/video/VID1/LCD/brightness
CURRENTLEVEL=`grep 'current:' $DEVICE | awk '{print $2}'`
if [ "x"$CURRENTLEVEL = "x0" ]; then
  CURRENTLEVEL=100
fi
SORTEDLEVELS=`grep 'levels:' $DEVICE | sed -e s,levels:,,g \
  -e 's,\s,\n,g' | sort -n -r | uniq | grep -v '^$' \
  | sed s,\n,\ ,g | xargs echo`
for levels in `echo $SORTEDLEVELS | sed 's,\n,\ ,g'`
do
    if [ $CURRENTLEVEL = $levels ]; then
      echo -n $LASTLEVEL > $DEVICE
      break
    fi
    LASTLEVEL=$levels
done

Remember to chmod your files, and chown them!

chmod 755 /etc/acpi/video_brightnessup.sh
chmod 755 /etc/acpi/video_brightnessdown.sh
chown root.root /etc/acpi/video_brightnessup.sh
chown root.root /etc/acpi/video_brightnessdown.sh
I hope these scripts work for you, and save you some of the headache I was experiencing!

The following flowchart says quite a bit about software development on the whole, and why it’s so easy to fail; it’s almost 100% true for any system with more than one programmer – and that single programmer often resorts to adding hacks upon hacks upon hacks just to make something work, leaving an ill-maintained piece of code.

Well, OK, I won the prize.

I won some goodies!


I won the door prize at the local semi-upscale supermarket. It has a bottle of wine, chocolate, cookies, cake, and some multigrain snacks.

(Yes, I know my grout is ugly; it’s two different shades. Why they did that, I don’t know.)

Bored this evening, I've not so much reinvented the wheel, as invented another way to use it.

%time php z63test.php /usr/share/dict/american-english
Normal length: 931467 bytes.
z63 length: 336720 bytes... 63% smaller!
Uncompressed length: 931467 bytes.
php z63test.php /usr/share/dict/american-english  0.28s user \
  0.02s system 99% cpu 0.304 total
Yes, you've seen that correct. It took less than .3 seconds on my 1Ghz laptop to compress almost 1MB of data down to about a third of it's size - into an XML compatible data format, then back into it's original form entirely in PHP!

The system cleanly degrades; if compression won't help, it won't force it. It will, however, continue to encode the string, so it's transferable via web-enabled applications.. You can even feed it binary data; it's even unicode clean (that's what it's primarily designed for, enabling binary data to be safely encapsulated, with less overhead than existing schemes.)

The result speaks for itself (Note that this data is rather worthless; it's just a free-form example):

Z63:
<?xml version="1.0" standalone="yes"?>
<FileData>
  <FileName>/usr/dict/words</FileName>
  <FileDate>2005-12-20T12:58:58-06:00</FileDate>
  <FileMD5>e954ccd9535d5550d8b632972b5a10ed</FileMD5>
  <FileBytes>931467</FileBytes>
</FileData>
<PassData>
  <Date>2007-11-26T07:26:57-06:00</Date>
  <MD5>03a43176887b657f90eab09e177c3a7d</MD5>
  <Bytes>336720</Bytes>
  <DataBlob>...</DataBlob>
</PassData>

Base64:
<?xml version="1.0" standalone="yes"?>
<FileData>
  <FileName>/usr/dict/words</FileName>
  <FileDate>2005-12-20T12:58:58-06:00</FileDate>
  <FileMD5>e954ccd9535d5550d8b632972b5a10ed</FileMD5>
  <FileBytes>931467</FileBytes>
</FileData>
<PassData>
  <Date>2007-11-26T07:27:36-06:00</Date>
  <MD5>bf1ecb99327ce7fb1f7496751039ea19</MD5>
  <Bytes>1241956</Bytes>
  <DataBlob>...</DataBlob>
</PassData>


Heck, it even compresses the front page of my website pretty well.
%time php z63test.php http://www.holwegner.com/
Normal length: 9911 bytes.
z63 length: 5077 bytes... 48% smaller!
Uncompressed length: 9911 bytes.
php z63test.php http://www.holwegner.com/  0.03s user \
  0.03s system 6% cpu 0.924 total