Debian and recent linux kernel on N810


Even if it did not (already) happen to me, there is no guarantee you will not lose your data and/or your system when trying to do the following. You have been warned.

In this howto, we detail the installation and configuration process of a fully functional Debian system on an external 8GB SDHC card (SD cards over 2GB must be SDHC compatible) of a N810. This includes the configuration and compilation of a recent kernel (2.6.30-rc8-omap1, at the moment).

Even if all the steps are provided on this single page, the howto is split into two main parts: system installation/configuration and kernel configuration/build/installation. I suggest you read the whole howto once before starting the installation of the system.

I make the hypothesis that you are already familiar with your device (enabling R&D mode, becoming root, installing a new kernel using flasher, ...), Debian distribution, and know how to configure and build a kernel.

Except for the kernel part, I used this post as a starting point.


Foreword (don't bother, skip directly to next section).

In December 2007 (when it was released in France), I bought a Nokia N810, for the following reasons ...:

... and with the following goals in mind:

N810 file system layout

Some notes on the layout of the internal flash of the N810, mainly useful to understand kernel size limitations.

cat /proc/partitions 
major minor  #blocks  name

  31     0        128 mtdblock0
  31     1        384 mtdblock1
  31     2       2048 mtdblock2
  31     3       4224 mtdblock3
  31     4     255360 mtdblock4
 254     0    7862272 mmcblk0
 254     1    7269381 mmcblk0p1
 254     2     586372 mmcblk0p2
 254     8    1966080 mmcblk1
 254     9    1966072 mmcblk1p1

As discussed here, /dev/mtdblock2 contains the compressed kernel image after an initial 2048 (0x800) bytes header (starting with "NOLO img")

The size of the partition is 0x200000 bytes, i.e. (2097152).

Taking a closer look at the dump, current compressed kernel image stored on the fielsystem consumes only 1.5Mbytes. Basically, the kernel compressed image cannot be larger than 2Mbytes (0x200000-0x800, i.e. 2046KB).

Partitioning the external card

Even if you can do the partitioning on your N810 (for instance by using sfdisk provided by e2fsprogs package), it is probably easier to do that on a real system using a graphical tool, like gparted.

We partition the card in the following way: first partition is a 7.5 GB ext3 partition and the remaining available space (500 MB) is used for swap. At the end of the process, the layout of the card looks like the following:

$ sudo fdisk /dev/mmcblk0

Command (m for help): p

Disk /dev/mmcblk0: 8050 MB, 8050966528 bytes
255 heads, 63 sectors/track, 978 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x000be52a

        Device Boot      Start         End      Blocks   Id  System
/dev/mmcblk0p1               1         914     7341673+  83  Linux
/dev/mmcblk0p2             915         978      514080   82  Linux swap / Solaris

Now, if you try and directly insert the card in your N810, it will not be mounted automatically. The set of scripts provided by maemo to perform the mount needs to be modified to handle ext3 partitions (initially, it supports only fat and ext2 filesystems).

Also note that it is pointless to modify the /etc/fstab on the N810 because it is not used in the mount process of the external card.

The mount of the card is done by /usr/sbin/ Adding support for ext3 is basically done by extending it in the following way, to load required modules and then call mount with the correct arguments:

---        2009-06-01 14:06:16.000000000 +0200
+++     2009-06-01 14:05:56.000000000 +0200
@@ -48,6 +48,18 @@
 mmc-mount $PDEV $MP
 if [ $RC != 0 ]; then
+  # Let's try ext3 - need to load modules
+  KERNEL_VERSION=`uname -r`
+  if install_module $KERNEL_VERSION mbcache; then
+    if install_module $KERNEL_VERSION jbd; then
+      if install_module $KERNEL_VERSION ext3; then
+        mount -t ext3 -o noatime,data=writeback $PDEV $MP > /dev/null
+        RC=$?
+      fi
+    fi
+  fi
   if [ $RC != 0 ]; then
     if install_module $KERNEL_VERSION ext2; then
       mount -t ext2 $PDEV $MP > /dev/null

I found the existence of and the initial idea to extend it here

After those changes, inserting the card should allow you to get the following:

# mount | grep ext3
/dev/mmcblk1p1 on /media/mmc1 type ext3 (rw,noatime,data=writeback)

Installing a boot menu

Before starting the installing process, we first handle the installation of a boot menu providing the ability to select the system to boot at startup. In our case, the Debian on our external SDHC card.

This process is straigthforward using the steps provided on Fanoush's web site. This simply requires sudo (or another way to get root on your N810) and possibly wget (to grab initfs_flasher and various additional things in the rest of the howto). We do that from a simple terminal on the tablet.

We first get initfs_flasher:

$ sudo bash
# mkdir /tempo
# cd /tempo
# wget
# tar xzvf initfs_flasher.tgz
# cd initfs_flasher
# less README.txt         # read it before doing anything else

Now that you are familiar with the tool (less README.txt, remember?), you are ready to create your own configuration file (based on bootmenu.conf.n8x0.example), in order to boot the system on the first partition of the ext3 formatted external SDHC card:

# cat > bootmenu.conf
# bootmenu customisation file
# included from after default menu is defined
# you can change some items or redefine menu completely

# timeout for automatic selection when no key is pressed
# set to -1 for no timeout (not recommended, can drain battery when device reboots unatteded)

# IP address for USB networking

# dim screen when in menu
#/usr/sbin/dsmetest -l 1 #for OS2006/7
#/usr/sbin/dsmetest -l 3 #for OS2008, 1 turns screen completely off

# menu items
MENU_MIN=1 # first item index

#no need to redefine
#MENU_1_NAME="Internal flash"

MENU_2_NAME="Internal MMC card, partition 2, ext2"
MENU_2_MODULES="mbcache ext2"
[ -d "/sys/block/${INT_CARD}/${MENU_2_DEVICE}" ] || MENU_2_NAME="(${MENU_2_NAME}) N/A"

MENU_3_NAME="Internal MMC card, partition 3, ext2"
MENU_3_MODULES="mbcache ext2"
[ -d "/sys/block/${INT_CARD}/${MENU_3_DEVICE}" ] || MENU_3_NAME="(${MENU_3_NAME}) N/A"

MENU_4_NAME="External MMC card, partition 1, ext3"
MENU_4_MODULES="mbcache jbd ext3"
MENU_4_FSOPTIONS="noatime" #",data=writeback"
[ -d "/sys/block/${EXT_CARD}/${MENU_4_DEVICE}" ] || MENU_4_NAME="(${MENU_4_NAME}) N/A"

MENU_5_NAME="Power off (when not on charger)"

#last item index, change if you add/remove items

Then, we simply call initfs_flash. It will automatically use previously created bootmenu.conf file:

# ./initf_flash

Well, it's not completely over yet. In fact, there is some changes you need to do on the script installed via previous procedure in order to deal with the fact that the event input device (/dev/input/eventX) for the N810 keyboard is /dev/input/event2 and not /dev/input/event0 on recent kernels.

Below are the changes I made to the script on my device:

PRODUCT=`awk '/product/ { print $2 }' /proc/component_version`
VERSION=`grep 'Linux version 2.6.30' /proc/version`

[ "$EVNAME" = "" ] && case $PRODUCT in SU-18) EVNAME=event1 ;; RX-34) EVNAME=eve
nt2 ;; RX-4[48]) EVNAME=event0 ;; esac
if [ "$VERSION" != "" ]; then


In order to make the changes to the script, do the following:

$ sudo bash
# mount -o rw,remount /mnt/initfs
# emacs -nw /mnt/initfs/         # do the changes
# mount -o ro,remount /mnt/initfs
# reboot

Well, it's not completely over yet. We need to handle the following issue in order to be able to interact with the boot menu. Basically, evkey binary segfaults:

root@oslo:/usr/bin# cd /mnt/initfs/usr/bin/
root@oslo:/mnt/initfs/usr/bin# strace ./evkey -u -t 1000 /dev/input/event2
execve("./evkey", ["./evkey", "-u", "-t", "1000", "/dev/input/event2"], [/* 19 vars */]) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B0 -opost -isig -icanon -echo ...}) = 0
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++

To correct that issue, I grabbed evkey.c file (here), and recompiled it (after removing the useless linux/bitops.h inclusion). Note that I had to create a static binary in order for it to work correctly:

$ gcc -o evkey evkey.c
$ ldd evkey => /lib/ (0x40034000)
        /lib/ (0x40000000)
$ gcc -static -o evkey evkey.c
        not a dynamic executable
$ mv evkey /mnt/initfs/usr/bin/evkey2

Then, you need to modify in order to use evkey2 when booting the 2.6.30-rc8 kernel

Forcing bootmenu to spawn by default during the boot process

Forcing bootmenu to spawn during the boot process by default, i.e. w/o having to interact with the keyboard:

# chroot /mnt/initfs cal-tool --set-root-device ask

This will be understood by bootmenu so that you do not need to push the menu button to get the menu displayed.

If you need to debug key related issues debugging bootmenu:

$ sudo bash
# mount -o rw,remount /mnt/initfs
  modify key_debug in
# mount -o ro,remount /mnt/initfs
# reboot

Installing debootstrap on the N810

In order to install our Debian system, we will use debootstrap. As debootstrap is only a set of scripts and has no specific architecture (processor) dependency; reusing current debian package for instance is fine. The only thing needed is to satisfy the package dependencies, i.e. mainly binutils. The official Maemo packages repository already provides the binutils package, so there is no need to look for complicated solution. For debootsrap, a simple search on Google (keywords "debian debootsrap armel") will almost directly provide you a link to current version of debootstrap package. In the end:

# cd /tmp
# apt-get install binutils
# wget
# dpkg -i debootstrap_1.0.13_all.deb

After those steps, debootstrap is not yet usable. The reason is that it relies on the availability of md5sum binary on the system, which is usually provided via coreutils package. On the N810, busybox is used as a more simple replacement for coreutils and prevents the installation of the package. Let's cheat a bit by getting current Debian armel coreutils package and extracting md5sum binary from the archive to copy it where it belongs:

 # cd /tmp
 # wget
 # dpkg-deb -x coreutils_7.3-1_armel.deb coreutils
 # cd coreutils
 # find . -name md5sum
 # cp ./usr/bin/md5sum /usr/bin/md5sum

Obviously, the version grabbed above using wget may not be available anymore on Debian repository. Find out which one is the most recent and use that one.

Using debootstrap to install Debian

If you followed previous steps (partitioning, mount scripts update and debootstrap installation), you should now be ready to use debootstrap to install a Debian on the ext3 partition of your external card, directly from Maemo.

Quite obviously, you need to be connected to the Internet for debootstrap to be able to fetch the packages.

Verify which partition you will use and where it is mounted:

# mount | grep ext3
/dev/mmcblk1p1 on /media/mmc1 type ext3 (rw,noatime,data=writeback)

Let's now install our Debian sid for armel architecture using a close mdebian mirror. Because adding additional packages with complex dependencies may result in a failed installation, you should definitely not add all the packages you intend to install later using the '--include' option. Instead, just let the base installation complete and do it later. Here is what I used:

 # debootstrap --include="sudo"
               --arch=armel sid /media/mmc1
  I: Retrieving Release
  I: Validating Packages
  I: Resolving dependencies of required packages...
  I: Resolving dependencies of base packages...
  I: Found additional required dependencies: libdb4.7 
  I: Checking component main on
  I: Retrieving adduser
  I: Validating adduser
  I: Retrieving apt
  I: Validating apt

This will take a loooooooong time, even if your Internet connection is not limiting, so be patient.

Once the installation has completed, there are additional steps you need to do before rebooting on your freshly installed system. They are listed in the following sections and need to be performed after having mounted some useful filesystem elements and having chrooted into /media/mmc1:

# mount /proc /media/mmc1/proc/
# mount /sys /media/mmc1/sys
# mount /dev /media/mmc1/dev
# mount /dev/pts /media/mmc1/dev/pts/
# cd /media/mmc1
# chroot /media/mmc1

Writing a valid fstab for the newly installed system

The /etc/fstab of our debian is empty. Let's correct that:

# cat > /etc/fstab
proc            /proc           proc    defaults                        0       0
/dev/mmcblk0p1  /               ext3    noatime,errors=remount-ro       0       1
/dev/mmcblk0p2  swap            swap    defaults                        0       0


Configuring apt to use required repositories

(In the chroot,) we start by configuring apt: the list of sources, pinning information for all repositories to be handled correctly, additional options (preventing the IMHO annoying use of Pdiffs for updates):

# cat > /etc/apt/sources.list

# Debian
deb unstable main contrib non-free
deb-src unstable main contrib non-free

# Mer alpha
deb alpha contrib main non-free
deb-src alpha contrib main non-free

#Ubuntu N8x0
deb alpha contrib main non-free
deb-src alpha contrib main non-free

# Deblet sid
deb sid main contrib non-free
deb-src sid main contrib non-free

# cat > /etc/apt/preferences

Package: *
Pin: release a=unstable,o=Debian,l=Debian
Pin-Priority: 900

Package: *
Pin: release a=alpha,l=mer-unstable
Pin-Priority: 340

Package: *
Pin: release a=alpha,l=ubuntu-unstable
Pin-Priority: 339

Package: *
Pin: release a=sid,l=deblet_unstable
Pin-Priority: 300
# cat > /etc/apt/apt.conf

Acquire::Pdiffs "false";

Sadly, not all of those repositories have their GPG key information available to import it into apt using apt-key. The one on Deblet sid repository is available, so we use it to show the process:

 # cd /tmp/
 # wget
 # apt-key add repo.key

It is not critical for the rest of the installation but you should be aware that apt will warn you for the packages it is unable to authenticate because associated repositories' keys have not been imported.

Installing the rest of the system

Now that apt is configured correctly, let's install the remaining packages. I decided to separate the installation in various command calls in order to comment what we install and why.

After having populated the /etc/apt/sources.list, we need to have apt update the list of packages available from associated repositories:

# apt-get update

bzip2 is needed and there is some chances your Debian system is complaining about locales, so let's correct that:

# apt-get install bzip2 locales
# dpkg-reconfigure locales

Let's install Xorg:

# apt-get install xserver-xorg-core xserver-xorg-video-omapfb

I am a sawfish/emacs guy. I don't think that gdm is the right solution (many dependencies and long to show up) for such a small devices as the N810 but at least it works fine. At some point I will probably update the howto in order to provide an alternative solution (no display manager but a password protected screen saver ?). Anyway:

# apt-get install emacs22 emacs22-el gdm sawfish xterm     

Because the console output is not available on the screen during the boot process, I find it useful to install some splash screen in order to get a progression bar. ubuntu-omap-fb package basically provides that feature

# apt-get install ubuntu-omap-fb-splash

In order to be able to use the WLAN and bluetooth chips (among others), some proprietary firmwares are needed. They have been packaged (Nokia has granted the right to do that AFAIK) and those will be copied to /lib/firmware/ (this is where recent kernels look for those firmware) when installing nokia-n8x0-firmware.

# apt-get install nokia-n8x0-firmware

# apt-get install dsme-tools

For the touchscreen to be usable, you need to install the following package which provides calibration information (/etc/pointercal) based on the specific hardware of the N810. The file is used by ts_calibrate (provided by libts-bin package) at startup.

# apt-get install nokia-tablets-pointercal

A small app to control the backlight of the screen. It provides a gnome menu entry and a Xsession script for the backlight to be set to the stored value when the user logs in (stored in ~/.brightness):

# apt-get install tablet-backlight

The keyboard of the N810 is quite specific in term of layout. It requires a specific symbols file (rx-44) in order to be usable. This file is available via the following package. Note that a specific section of the howto is dedicated to the complete keyboard configuration:

# apt-get install nokia-xkb-data

The following package will install an init script (to tweak some /proc and /sys values. You need to edit the installed init script and remove/comment the first test of tablet_setup() function to prevent the boot process to be stopped. I intend to provide a replacement for those package, as it is intended for booting an ubunutu using a linuxrc script.

# apt-get install nit-bootmenu-compat

We install Xorg touchscreen module and associated tools:

# apt-get install xserver-xorg-input-tslib libts-bin

Before the keyboard is fully configured, you may find a virtual keyboard useful:

# apt-get install matchbox-keyboard

Provide a valid configuration file for Xorg

# cat > /etc/X11/xorg.conf 

Section "InputDevice"
        Identifier      "Generic Keyboard"
        Driver          "kbd"
        Option          "XkbRules"      "xorg"
        Option          "XkbModel"      "pc105"
        Option          "XkbLayout"     "us"

Section "InputDevice"
        Identifier "tslib"
        Driver "tslib"
        Option "ScreenNumber"   "0"
        Option "Width"          "800"
        Option "Height"         "480"
        Option "Rotate"         "NONE"
        Option "TslibDevice"    "/dev/input/event3"
        Option "CorePointer"

Section "Device"
        Identifier      "Configured Video Device"
#       Option          "UseFBDev"              "true"
        Driver          "omapfb"
        Option          "fb" "/dev/fb0"

Section "Monitor"
        Identifier      "Configured Monitor"

Section "Screen"
        Identifier      "Default Screen"
        Monitor         "Configured Monitor"


Modify /etc/rc.local

Add the call to "/sbin/fb_update_mode auto" before the "exit 0". It should then look like the following:

# cat /etc/rc.local
 #!/bin/sh -e
 # rc.local
 # This script is executed at the end of each multiuser runlevel.
 # Make sure that the script will "exit 0" on success or any other
 # value on error.
 # In order to enable or disable this script just change the
 # bits.
 # By default this script does nothing.
 /sbin/fb_update_mode auto
 exit 0

Reconfiguring the timezone

This can be done in the following way:

dpkg-reconfigure tzdata

Installing a boottime.kmap.gz


Hardware clock

modify /etc/init.d/ and change HWCLOCKPARS= to HWCLOCKPARS="--directisa". Then:

# echo 'HWCLOCKPARS=--directisa' >> /etc/default/rcS

XXX Spend time on that

Force automatic fixing by fsck

Change the content of /etc/defaut/rcS to have FSCKFIX=yes

XXX FIXME see if this is really a good idea

bypass /etc/rcS.d/S10checkroot

XXX I did not had time to investigate the problem specifically but /etc/init.d/checkroot script prevents the boot process to complete for some reason. At the moment, I just commented the call to do_start function. This is a *temporary* workaround.

Compiling a recent kernel for your N810

Foreword (read it)

Let's be clear. If you intend to compile a recent kernel (say 2.6.30-rc8 as in this howto) for your N810, then there are two things you should know beforehand:

Installing a recent version of gcc-4.X-arm-linux-gnueabi

For the reasons explained below, let's first install a recent version of gcc-4.X-arm-linux-gnueabi. If you use Debian as your development environment (I suspect this is also the case under other common distributions), you will quickly notice that there is no package available providing what you are looking for.

Among other things, the people at maintain packages of toolchains to build for arm, ia64, m68k, mips, mipsel, powerpc and sparc using gcc-3.3, gcc-3.4, gcc-4.0, gcc-4.1, gcc-4.2 and later versions. Take a look at following page before going further.

After adding the following to the /etc/apt/sources.list on your development box ...

deb unstable main

... you just need to

$ sudo apt-get install gcc-4.2-arm-linux-gnueabi 

Note that I am using gcc-4.2-arm-linux-gnueabi as I know it does work fine with the 2.6.30-rc8-omap1 version I compile.

Cloning linux-omap tree

Now that we have a toolchain to build for arm, let's clone linux-omap tree to get something to compile.

$ git://

Finding a usable commit

Well, you just cloned a development tree. You did not expect current tip would work, did you? After trying various versions, I ended up on a post 2.6.30-rc8 commit: 151c7a7fc30cceb58e7999adbf3ad5e0c734b4a7

commit 151c7a7fc30cceb58e7999adbf3ad5e0c734b4a7
Merge: 944f942 9fa7eb2
Author: Tony Lindgren <>
Date:   Wed Jun 3 10:05:50 2009 -0700

    Merge current mainline tree into linux-omap tree
    Merge branches 'master' and 'linus'

commit 944f94235969c15b3012aa4dc832ed3e2f08e4da
Author: Amit Kucheria <>
Date:   Wed Jun 3 09:53:24 2009 -0700

    twl4030: Add some error checking to twl4030 init
    Check for return values of i2c read/write operations and size of scripts bei
    uploaded to TWL4030
    (Removed the unrelated string changes based on David Brownell's comment)
    Signed-off-by: Amit Kucheria <>
    Signed-off-by: Tony Lindgren <>

commit 9fa7eb283c5cdc2b0f4a8cfe6387ed82e5e9a3d3
Author: Linus Torvalds <>
Date:   Tue Jun 2 20:07:25 2009 -0700

    Linux 2.6.30-rc8


Creating a first kernel configuration (.config) file

Usually, you would do the following:

CROSS_COMPILE=arm-linux-gnueabi- make n800_defconfig

but this will simply not work. I mean the resulting kernel does not boot on my device. I suspect this is related to the fairly recent addition of CONFIG_ARM_UNWIND option and the fact it is activated by default:


This option enables stack unwinding support in the kernel
using the information automatically generated by the
compiler. The resulting kernel image is slightly bigger but
the performance is not affected. Currently, this feature
only works with EABI compilers. If unsure say Y.

Symbol: ARM_UNWIND [=n]
Prompt: Enable stack unwinding support
  Defined at arch/arm/Kconfig.debug:18
    -> Kernel hacking

I use this config for my 2.6.30-rc8. It has ext3, WLAN and everything needed for MIPv6 (including IPsec) compiled statically. The device boots and you can use it as a starting point to build you own kernel.

Compiling your the kernel

Type the following after having created a kernel configuration and wait for some minutes:

CROSS_COMPILE=arm-linux-gnueabi- make

The compressed kernel image is now available at arch/arm/boot/zImage.

Flashing your device with your new kernel

You first need to download a recent version of flasher tool on that page. I use flasher-3.0. Once you have downloaded and made it available in your PATH, you are ready to flash your device:

$ sudo flasher-3.0 -k arch/arm/boot/zImage  -f -R
flasher v0.8.7 (Oct 17 2006)

Suitable USB device not found, waiting

Linux 2.6.30-rc8 keyboard issue patch

This is discussed here and the patch below was posted here.

Index: linux-omap-2.6/arch/arm/mach-omap2/board-n800.c
--- linux-omap-2.6.orig/arch/arm/mach-omap2/board-n800.c	2009-06-13 12:17:40.000000000 +0200
+++ linux-omap-2.6/arch/arm/mach-omap2/board-n800.c	2009-06-13 12:18:17.000000000 +0200
@@ -117,7 +117,7 @@
 	.repeat		= 0, /* Repeat is handled in userspace for now. */
 	.keymap		= rx44_keymap,
 	.size_x		= 8,
-	.size_y		= 8,
+	.size_y		= 12,
 	.debounce_time	= 12,
 	.active_time	= 500,

Handling keyboard layout

Recent version of Xorg (at least under recent version of Debian) do not listen anymore to what you put in your /etc/X11/xorg.conf regarding your keyboard configuration.

In fact, by default, with recent version of Xorg, keyboard layouts and variants are overridden by hal. But in fact, real default is for Xorg to use the keyboard information provided by console-setup package, i.e. by the options configured in /etc/default/console-setup.

I put the following in mine, in order to use the french (fr) variant found in /usr/share/X11/xkb/symbols/nokia_vndr/rx-44.


  # The following variables describe your keyboard and can have the same
  # values as the XkbModel, XkbLayout, XkbVariant and XkbOptions options
  # in /etc/X11/xorg.conf.

Note that rx-44 file has been installed here via the installation of xkb-data package.

After a reboot, previous values should appear in your /var/log/Xorg.0.log:

(II) Internal keyboard: Configuring as keyboard
(II) XINPUT: Adding extended input device "Internal keyboard" (type: KEYBOARD)
(**) Option "xkb_rules" "evdev"
(**) Option "xkb_model" "pc105"
(**) Option "xkb_layout" "nokia_vndr/rx-44"
(**) Option "xkb_variant" "fr"
(**) Option "xkb_options" "lv3:ralt_switch"
(II) config/hal: Adding input device TSC2005 touchscreen
(**) TSC2005 touchscreen: always reports core events

Fn key issue

After your first boot on your N810, you will notice that your Fn key simply does not work as expected. You will probably try and launch xev to see what keycode/scancode/keysym/... it returns. The response is simply: none.

Why? Well, the kernel keymap for the N810 (in arch/arm/mach-omap2/board-n800.c) is simply written so that the value 464 (0x1d0) is returned as keycode value to X when the key is pressed.

The thing is that Xorg does not handle (drops, in fact) keycodes over 255. If you are interested by the topic, there are information on the topic here, here, here and here.


To correct that I wrote a simple kernel patch to have Fn key (KEY_FN) advertise itself as a left alt key (KEY_LEFTALT):

Index: linux-omap-2.6/arch/arm/mach-omap2/board-n800.c
--- linux-omap-2.6.orig/arch/arm/mach-omap2/board-n800.c	2009-06-20 12:07:11.000000000 +0200
+++ linux-omap-2.6/arch/arm/mach-omap2/board-n800.c	2009-06-27 20:29:00.000000000 +0200
@@ -85,7 +85,11 @@
 	[0x22] = KEY_SEMICOLON,
 	[0x23] = KEY_MINUS,
 	[0x24] = KEY_EQUAL,
+	[0x2b] = KEY_LEFTALT,
 	[0x2b] = KEY_FN,
 	[0x2c] = KEY_M,
 	[0x2f] = KEY_F8,
Index: linux-omap-2.6/drivers/input/keyboard/Kconfig
--- linux-omap-2.6.orig/drivers/input/keyboard/Kconfig	2009-06-20 12:07:11.000000000 +0200
+++ linux-omap-2.6/drivers/input/keyboard/Kconfig	2009-06-20 12:07:35.000000000 +0200
@@ -294,6 +294,20 @@
 	  If you say yes here you get support for the National Semiconductor
 	  LM8323 keypad controller.
+config REMAP_N810_FN_KEY
+       boolean "Nokia N810 keyboard Fn key remapping"
+       depends on MACH_NOKIA_N810 && KEYBOARD_LM8323
+       help
+          If you build your kernel for your Nokia N810 (which would
+	  possibly explain you selected LM8323 keypad chip above),
+	  you might want to select this option in order to have the
+	  Fn key (KEY_FN) advertise itself as left alt key
+          (KEY_LEFTALT).
+	  This is because KEY_FN value is higher than 255, and Xorg
+	  basically drops those values. Selecting the option allows
+	  you to use the key under X
 config KEYBOARD_PXA27x
 	tristate "PXA27x/PXA3xx keypad support"
 	depends on PXA27x || PXA3xx

Then, it's just a matter of modifying the rx-44 keymap in order to change change the <FN> for <LALT>.

Keyboard remapping

Here is my rx-44 file