Now that more drivers are being converted to load firmware at initialisation time, curmudgeons like me who prefer to build a non-modular kernel are increasingly troubled. Fortunately, initramfs allows us to stick with what we know instead of having to deal with these newfangled module thingies. If you're using a distro that has its own initramfs scripts, you should probably follow their method. But if you're the kind of person who builds their own custom kernels, this howto is just what you're looking for. Here's how to get things working. First, you need to replicate what the kernel would put into your initramfs. Starting from the root of an unpacked kernel tree, put these three lines into usr/default-files: dir /dev 0755 0 0 nod /dev/console 0600 0 0 c 5 1 dir /root 0700 0 0 Second, create the directory structure for our initramfs: mkdir usr/root usr/root/firmware usr/root/sbin usr/root/bin usr/root/sys Third, get some firmware to put in it. I'll use the qlogic firmware in this example: wget -P usr/root/firmware ftp://ftp.qlogic.com/outgoing/linux/firmware/ql2300_fw.bin Fourth, we need something to load that firmware. We could write this as a compiled binary (or a perl/python/ruby/... script), but a shell script is traditional. I used Documentation/firmware_class/hotplug-script as a base for this, but it needs some modifications (to mount sysfs and to cope with being called for non-firmware events. Place the following script in usr/root/sbin/hotplug: #!/bin/sh load_firmware() { if [ ! -e /firmware/$FIRMWARE ]; then echo $FIRMWARE not found >/dev/console return fi echo Loading $FIRMWARE into $DEVPATH >/dev/console mount -t sysfs sysfs /sys echo 1 > /sys/$DEVPATH/loading cat /firmware/$FIRMWARE > /sys/$DEVPATH/data echo 0 > /sys/$DEVPATH/loading umount /sys } case $ACTION in add) case "$FIRMWARE" in "") ;; *) load_firmware ;; esac ;; esac Fifth, we need a POSIX shell to run it. sash won't do, as it doesn't support redirection; I ended up using busybox-static, but you can use whatever you like as long as it's static or you add the dynamic linker and the libraries it uses. cd usr/root wget ftp://ftp.us.debian.org/debian/pool/main/b/busybox/busybox-static_1.1.3-3_ia64.deb ar x busybox-static_1.1.3-3_ia64.deb rm control.tar.gz debian-binary busybox-static_1.1.3-3_ia64.deb tar -zxf data.tar.gz rm -rf usr ln -s busybox bin/sh rm data.tar.gz cd ../.. Sixth, change CONFIG_INITRAMFS_SOURCE to "usr/default-files usr/root", the CONFIG_INITRAMFS_ROOT_UID and CONFIG_INITRAMFS_ROOT_GID as appropriate, and run make. You should now be able to boot your kernel and have firmware load at initialisation time. NOTE! A couple of the things I mention here don't work right. You need to apply this patch to current Linus kernels: http://www.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.19-rc5/2.6.19-rc5-mm2/broken-out/initramfs-handle-more-than-one-source-dir-or-file-list.patch Also, echoing to /dev/console doesn't work. I don't know why. This makes debugging hard.