This morning I have learned a lot about HAL. I have been trying to get the brightness up/down controls on my laptop to work (they need to use a non-standard Nvidia interface).

If you have the same laptop then these are the steps I went through to get it work. Disclaimer: your mileage may vary; no warranty; may be somewhat Arch Linux specific.

First we need to make sure the kernel sends the right key symbols, which it doesn’t by default. Add the following to /etc/rc.local

setkeycodes e008 225 e009 224

Here e008 and e009 are the scancodes, and 225 and 224 are the keysyms we want them translated to.

Next we need to get HAL to recognize the Samsung Q320 and handle it specially. Copy 10-samsung-q320-brightness.fdi to /etc/hal/fdi/information/.

Now restart HAL and this file should be loaded (you can check with /usr/lib/hal/hald-generate-fdi-cache --verbose 2>&1 | grep samsung). This does two things: it sets the access_method for the brightness control to a special value “samsung-q320” rather than the default “generic” – we’ll check for this later; it also removes the key that tells HAL to look for the brightness control under /sys – this doesn’t work. Check this has worked by running lshal | grep samsung-q320.

Now, HAL uses two scripts to handle getting and setting the brightness. These are hal-system-lcd-get-brightness and hal-system-lcd-set-brightness located in /usr/lib/hal/scripts. We’re going to hack them so they use smartdimmer (from the nvclock package). Apply this patch to hal-system-lcd-get-brightness:

--- hal-system-lcd-get-brightness.old   2009-07-07 11:42:25.000000000 +0100
+++ hal-system-lcd-get-brightness       2009-07-07 13:10:17.000000000 +0100
@@ -9,6 +9,10 @@
 . hal-functions
+if [ "$HAL_PROP_LAPTOP_PANEL_ACCESS_METHOD" = "samsung-q320" ]; then
+       exit `smartdimmer -g | awk '/SmartDimmer level: / {print int(($3 - 15) / 5)}'`
 # Check for environment variables
         echo "org.freedesktop.Hal.Device.UnknownError" >&2

This checks the special key we set earlier, and if it is set we query setdimmer for the current brightness and munge it into a number between 0 and 17 (there are 18 brightness levels on this backlight). A similar patch for hal-system-lcd-set-brightness:

--- hal-system-lcd-set-brightness.old   2009-07-07 11:28:32.000000000 +0100
+++ hal-system-lcd-set-brightness       2009-07-07 16:48:16.000000000 +0100
@@ -30,5 +30,10 @@
 export value
+if [ "$HAL_PROP_LAPTOP_PANEL_ACCESS_METHOD" = "samsung-q320" ]; then
+       smartdimmer -s `expr $value \* 5 + 15`
+       exit
 hal_check_priv org.freedesktop.hal.power-management.lcd-panel

Now you should be able to test this using any HAL-enabled brightness setter (e.g. GNOME Power Manager).

I had a strange problem with the GPM in Arch: it refused to change the brightness away from 50%. I got the GPM source from ABS to try and debug it, but when I built it from source it worked fine. Hmm.