To my homepageGerman
Did this site help you?
Average rating (h5450):
2.70/3 (148 votes)

Linux on the iPAQ H5450

...Linux in your hands

PDAs are handy for keeping track of appointments and addresses. That's why I used a PalmIII years ago. But since Palm hardware now seems a little bit rusty, I switched to the more modern iPAQ models made by HP/Compaq. They are quiet a leap ahead of my old Palm (Bluetooth, WLAN), but unfortunately, those devices run Windows CE by default. But there's no need to worry, since Familiar Linux brings our favorite OS on a tiny computer.


iPAQ with Familiar

The iPAQ H5450 contains the following hardware:

The linux support for this devices varies, although it is quite good. You may find up-to-date information at the wiki page on

Familiar Software

TuxMobil Listed
The issue 5'2005 of the FreeX magazine will feature an article by me about Linux on iPAQ devices.

Familiar is a linux distribution aimed at iPAQ devices and similar PDAs. It replaces the builtin WindowsCE installation with a linux system derived from the OpenEmbedded framework, including a proper package managemant system (ipkg, resembling Debian's dpkg/apt-get). The installation process is quite easy and just requires a serial connection to a notebook or PC (windows or linux), and there is a good howto here.

There is a lot of software available; I also managed to get my iPAQ connected to the VPN/WLAN of my university(German).

Tweaking & Tuning

Packages On External Media

You can install packages on external media once your flash memory gets crowded; To do so, format the media with a file system that supports the usual unix mechanisms (links, ownership, etc.), e.g. ext2. In most cases, the media will be mountet automatically. To install packages to your SD card or PCMCIA hard drive, add the following line to you /etc/ipkg.conf:

dest disk /media/disk/install/

In this case, /media/disk/ is the path where your media is mounted, and on which a directory installed/ resides. Depending on your hardware and setup, you have to adapt this path, e.g. to /mnt/card/installed/ for SD cards or /mnt/cf/installed/ for compact flash media.

To install packages to this destination, combine your ipkg command with the option -d disk. The files of the requested package will be installed with installed with /media/disk/installed/ as their root directory; The ipkg package database for those packages is also isolated from the normal one, it resides in /media/disk/installed/usr/lib/ipkg/.

To use the installed files from within your installation, you have to create symlinks from /media/disk/installed/ to you root directory. For this purpose, Familiar offers the ipkg-link command: Called as ipkg-link mount /media/disk/install/, it will link the files of all packages installed in /media/disk/installed/ to your root filesystem. To remove them again, simply use the same command with umount.

Although most packages accept this way of installation, problems arise if the scripts supplied with the package and executed on installation and removal try to do something with the files. Usual suspects for this are packages that supply init scripts.

Headphone Jack & Kernel Upgrade

Familiar 0.8.2 comes with the kernel version 2.4.19-rmk6-pxa1-hh37; Unfortunately, this release does not support headphone detection, so your headphone will remain silent. To use them, you have to install a newer version, 2.4.19-rmk6-pxa1-hh39 to be precise, which you can get from

Upgrading the kernel is tricky, since you have to install all corresponding module packages as well. First, try to make as much room as possible, uninstall big packages (e.g. the minimo web browser) to free space before the installation: Running out of space during package installation can get nasty. You can also also gain prescious memory by moving your package lists to Ramdisk by adding the line lists_dir ext /var/lists to your /etc/ipkg.conf. After having enough free space, add the new package repository to your configuration:

These sources seem to be outdated
src/gz kernel

To install all needed module packages, you can use the following command which will try to retrieve the hh39 counterparts to all installed hh37 packages:

ipkg -force-overwrite install $(ipkg list_installed | grep 2.4.19-rmk6-pxa1-hh37 | awk '{print $1}' | sed 's/-hh37/-hh39/')

The "-force-overwrite" option is necessary, since both the hh37 as well as the hh39 packages try to place files in /etc/modutils.

Through the dependency system the "kernel-image-2.4.19-rmk6-pxa1-hh39" itself should be installed automatically; You should make sure that the kernel is installed by looking at "zImage" file in /boot.

Once all packages are installed without trouble, edit the file "/boot/params" to boot the new kernel - just add the following line:

set kernel_filename boot/zImage-2.4.19-rmk6-pxa1-hh39

This way, in a case of emergency, you can still boot the old kernel by pressing the action button during boot, or you could influence the bootloader via serial console.

Once the new kernel has been bootet, thoroughly check the functionality of your ipaq - did you install the new wlan modules, or are there other packages missing? If you are really sure that everything is working, you can remove the old kernel with the command ipkg remove kernel-image-2.4.19-rmk6-pxa1-hh37; Most module packages should be uninstalled as well along with it, you can search for remaining ones with ipkg list_installed | grep 2.4.19-rmk6-pxa1-hh37.

Et voilà!: You got your Familiar with the new kernel, ready to support your headphone.

Unleashing the hidden flash memory

As you can read here, all H3970, H5450 and H5550 devices do have a hidden partition in flash memory that will give you another 16MB of "disk" space. All you have to do is install the package "mtd-utils" and follow the instructions.

No IP address from DHCP server via WLAN

Sometimes ifup wlan0 will not bring up the interface at once. This is because udhcpc will only try three times to get a valid lease from a dhcp server, but the WLAN interface takes 3-4 seconds until it is ready to transmit data. After three unanswered calls, udhcpc goesa into background and wait for another minute until it tries again to gain network information.

A solution is it to wait 3-4 seconds after configuring the WLAN interface, and before bringing up the DHCP client. To do this, append the line sleep 4 (or even more) to the file /etc/network/if-pre-up.d/wireless-tools. Also check the bugfixes below, especially the one addressing (and solving) this timing problem.

x2x, SSH and your iPAQ

It can come in quite handy to use a real keyboard and a mouse with your ipaq, especially if you are setting up some configuration files. With the utility x2x you can link two X11 displays, so you can move your mouse cursor to the edge of yor display, leading it to end up on the other display. You keyboard does travel with your pointer, so you completely take control of the other X-Server.

Since x2x relies on then plain X11 protocol, it only has to be installed on one computer; If you enter xhost +IP on the system going to be the controlled one, the program can connect to the X-Server on that computer. Opening your Xserver for external TCP connections is usuall a bad idea, so SSH tunneling should be used. But this not as easy as it sound: Between my notebook and my desktop computer, I can use the following line:

stefan@notebook:~$ ssh -X desktop 'x2x -from $DISPLAY -to :0.0'

The command is executed on my desktop, where $DISPLAY is the display generated by the X forwarding of SSH, and :0.0 the X-Server running on the desktop.

This elegant behaviour fails when applied to the iPAQ because of two reasons:

  1. There is no x2x package for Familiar
  2. The SSH session could be triggered the other way round, but the Dropbear SSH client does not support X11 forwarding

As a "hacky" solution, X11 forwarding can be emulated using the available port forwarding. Both the SSH process as well as the X2X instance will be running on the controlling computer.


# initialize the SSH connection, forward X11 port
ssh ipaq -L 60$SERVERNUM: -N &
x2x -from :0.0 -to localhost:$SERVERNUM.0
# kill the SSH tunnel
kill $SSHPID

After executing the script, a window labeled "localhost:20.0" will appear on the screen of the controlling computer. Clicking that window changes focus to the ipaq, all cursor movements and key events are now taking effect on the handheld device. If you want to switch back, place the cursor over the window again, and press your mouse buttons in consecutive order (left, middle, right). If you only have two buttons, press the left one, then both (for emulation of the middle one), then only the right one.

Bugs & Fixes


While playing with the installation and using the wlan, I noticed a strange bug surrounding the suspend feature: I was using multiple wlan profiles, so my »/etc/network/interfaces« consisted of several iface definitions with names like "home", "university", "work", while the wlan0 device was only defined as a mapping that used a script to decide which profile to use. Unfortunately, the "ifdown" part of Busybox could not handle the profiles: Whenever e.g. apmd called "ifdown wlan0", the ifdown process did not know what to do, since it was unable to lookup the right profile in »/var/run/ifstate«. This led to trouble, since the dhcp client was not killed by ifdown, or vpn-connection stayed open.

Although the correct approach would be a patch to Busybox, I created a wrapper script to complete the lone interface name with the loaded profile. To use it, create the directory »sbin/real/«, and place a link called »ifdown« in there pointing to the busybox binary in »/usr/bin/«. You then may remove the old »ifup« link in »/sbin/« and place the script there:

# This ifdown wrapper takes care of profiles associated with the
# physical network interface
# Move your real /sbin/ifdown to /sbin/real/ifdown
# (you cannot rename it, since busybox identifies the command by its name)
# by Stefan Tomanek (
# 2005-05-03



for i in $@; do
	if grep -q "^$i=" $IFSTATE; then
		#echo "Token $i is a network device without profile"
		PROFILE=$(grep "^$i=" $IFSTATE| cut -d= -f2)
		ARGS="$ARGS $i"
echo "Calling »$IFDOWN $ARGS«"

Last change: (Wednesday, 04-May-2005 15:51:13 CEST)

hotplug vs. apmd

Another issue arose between hotplug and apmd: On suspend, apmd saves the state of alle network interfaces and shuts them down (although incorrectly, but solved due to the ifdown wrapper). On resume, the interfaces will be brought up again with the same profile they where using before. But the hotplug agent - also trying to activate the interface - uses the generic interface name to start the interface: So we have two daemons fighting over our precious WLAN. To solve this, I patched hotplug's »/etc/hotplug/net.agent« to check whether the interface was deactivated by apmd; This is an excerpt of the critical new lines:

            # RedHat and similar
            export IN_HOTPLUG=1
            if [ -x /sbin/ifup ]; then
                debug_mesg invoke ifup $INTERFACE
                # Check whether the interface will be resumed by apmd on resume
                # In that case, do not touch it
                # Stefan Tomanek (
                if grep -q "^$INTERFACE=" /var/run/ifstate /var/run/ifstate-suspend; then
                        /usr/bin/logger "HOTPLUG: Interface $INTERFACE already configured"
                        /usr/bin/logger "HOTPLUG: bringing up $INTERFACE"
                        exec /sbin/ifup $INTERFACE

Last change: (Wednesday, 04-May-2005 16:01:23 CEST)

Waiting for the WLAN

As already mentioned, timing can be tricky when using DHCP for the wireless interface. The following script, placed at /etc/network/if-pre-up.d/zzz-wireless, will sleep until the wireless configuration has reached a stable association with an access point. If this connection is established, it passes on to the following scripts, usually udhcpc, which can now rely on an established connection. The name zzz-wireless does not only reflect the scripts function of putting the ifup process to a sleep, the z is also necessary to let it be executed after the standard wireless script /etc/network/if-pre-up.d/wireless-tools.

# /etc/network/if-pre-up.d/zzz-wireless
# by Stefan Tomanek (


# How long do we wait for association?

# Only sleep if we use DHCP (add others methods seperated by spaces)
ONLY_FOR="static dhcp"

if [ -z "$IF_WIRELESS_TYPE" ] && echo "$ONLY_FOR" | grep -q "$METHOD" ; then
	$LOGGER Checking for WLAN association...
	while ( [ $RETRIES -gt 0 ] && ($IWCONFIG "$IFACE" | $GREP -q "Access Point: 00:00:00:00:00:00") ); do
		$LOGGER No association yet, $RETRIES retries until timeout
	if [ $RETRIES -eq 0 ]; then
		$LOGGER Timeout waiting for association, continuing anyway...
		$LOGGER Found association!
Last change: (Saturday, 28-May-2005 20:10:13 CEST)