Argh! Another problem! Over the last couple of days I’ve being trying to figure out why the brightness fn-keys on my laptop don’t seem to work: they either set the brightness to maximum-bright or maximum-dim. (Although they inexplicably sometimes work.) At first I thought it was a problem with my earlier HAL hackery, but this isn’t the case as the HAL brightness scripts work fine when not using the fn-keys.

After a while I discovered the problem was that some of the fn-keys weren’t sending key release events (easy to see in xev or with lshal -m). Turns out this is a problem with lots of laptop keyboards: look at the thousands of lines of hacks in drivers/input/keyboard/atkbd.c in the Linux kernel source. The good news is that this is easy to fix: the Q320 uses exactly the same scancodes as an earlier Samsung laptop. The bad news is that you have to compile your own kernel. Ho hum.

Apply this patch to a 2.6.30 kernel and rebuild. Voila! And the problem is gone!

--- drivers/input/keyboard/atkbd.c.old  2009-07-13 00:34:14.000000000 +0100
+++ drivers/input/keyboard/atkbd.c      2009-07-13 00:35:19.000000000 +0100
@@ -1550,6 +1550,15 @@
                .driver_data = atkbd_samsung_forced_release_keys,
+               .ident = "Samsung Q320/P320",
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Q320/P320"),
+               },
+               .callback = atkbd_setup_forced_release,
+               .driver_data = atkbd_samsung_forced_release_keys,
+       },
+       {
                .ident = "Samsung SQ45S70S",
                .matches = {

I found the DMI_PRODUCT_NAME using dmidecode if you were wondering.

Will test it for a few days and if nothing is borked maybe I shall try to get it merged into the kernel. It would certainly be annoying to have to compile my own kernel for every release.