How does Linux Kernel know where to look for driver firmware?
Solution 1:
From the kernel's perspective, see /usr/src/linux/Documentation/firmware_class/README:
kernel(driver): calls request_firmware(&fw_entry, $FIRMWARE, device) userspace: - /sys/class/firmware/xxx/{loading,data} appear. - hotplug gets called with a firmware identifier in $FIRMWARE and the usual hotplug environment. - hotplug: echo 1 > /sys/class/firmware/xxx/loading kernel: Discard any previous partial load. userspace: - hotplug: cat appropriate_firmware_image > \ /sys/class/firmware/xxx/data kernel: grows a buffer in PAGE_SIZE increments to hold the image as it comes in. userspace: - hotplug: echo 0 > /sys/class/firmware/xxx/loading kernel: request_firmware() returns and the driver has the firmware image in fw_entry->{data,size}. If something went wrong request_firmware() returns non-zero and fw_entry is set to NULL. kernel(driver): Driver code calls release_firmware(fw_entry) releasing the firmware image and any related resource.
The kernel doesn't actually load any firmware at all. It simply informs userspace, "I want a firmware by the name of xxx", and waits for userspace to pipe the firmware image back to the kernel.
Now, on Ubuntu 8.04,
$ grep firmware /etc/udev/rules.d/80-program.rules # Load firmware on demand SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware_helper"
so as you've discovered, udev
is configured to run firmware_helper
when the kernel asks for firmware.
$ apt-get source udev Reading package lists... Done Building dependency tree Reading state information... Done Need to get 312kB of source archives. Get:1 http://us.archive.ubuntu.com hardy-security/main udev 117-8ubuntu0.2 (dsc) [716B] Get:2 http://us.archive.ubuntu.com hardy-security/main udev 117-8ubuntu0.2 (tar) [245kB] Get:3 http://us.archive.ubuntu.com hardy-security/main udev 117-8ubuntu0.2 (diff) [65.7kB] Fetched 312kB in 1s (223kB/s) gpg: Signature made Tue 14 Apr 2009 05:31:34 PM EDT using DSA key ID 17063E6D gpg: Can't check signature: public key not found dpkg-source: extracting udev in udev-117 dpkg-source: unpacking udev_117.orig.tar.gz dpkg-source: applying ./udev_117-8ubuntu0.2.diff.gz $ cd udev-117/ $ cat debian/patches/80-extras-firmware.patch
If you read the source, you'll find that Ubuntu wrote a firmware_helper
which is hard-coded to first look for /lib/modules/$(uname -r)/$FIRMWARE
, then /lib/modules/$FIRMWARE
, and no other locations. Translating it to sh
, it does approximately this:
echo -n 1 > /sys/$DEVPATH/loading
cat /lib/firmware/$(uname -r)/$FIRMWARE > /sys/$DEVPATH/data \
|| cat /lib/firmware/$FIRMWARE > /sys/$DEVPATH/data
if [ $? = 0 ]; then
echo -n 1 > /sys/$DEVPATH/loading
echo -n -1 > /sys/$DEVPATH/loading
fi
which is exactly the format the kernel expects.
To make a long story short: Ubuntu's udev
package has customizations that always look in /lib/firmware/$(uname -r)
first. This policy is being handled in userspace.
Solution 2:
Wow this is very useful information and it led me to the solution for my problem when making a custom USB kernel module for a device requiring firmware.
Basically, every Ubuntu brings a new rehash of hal,sysfs,devfs,udev,and so on...and things just change. In fact I read they stopped using hal.
So let's reverse engineer this yet again so it's pertinent to the latest [Ubuntu] systems.
On Ubuntu Lucid (the latest at time of writing), /lib/udev/rules.d/50-firmware.rules
is used. This file calls the binary /lib/udev/firmware
, where magic happens.
Listing: /lib/udev/rules.d/50-firmware.rules
# firmware-class requests, copies files into the kernel
SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware --firmware=$env{FIRMWARE} --devpath=$env{DEVPATH}"
The magic should be something along these lines (source: Linux Device Drivers, 3rd Ed., Ch. 14: The Linux Device Model):
- echo 1 to
loading
- copy firmware to
data
- on failure, echo -1 to
loading
and halt firmware loading process - echo 0 to
loading
(signal the kernel) - then, a specific kernel module receives the data and pushes it to the device
If you look at Lucid's source page for udev, in udev-151/extras/firmware/firmware.c
, the source for that firmware /lib/udev/firmware binary, that's exactly what goes on.
Excerpt: Lucid source, udev-151/extras/firmware/firmware.c
util_strscpyl(datapath, sizeof(datapath), udev_get_sys_path(udev), devpath, "/data", NULL);
if (!copy_firmware(udev, fwpath, datapath, statbuf.st_size)) {
err(udev, "error sending firmware '%s' to device\n", firmware);
set_loading(udev, loadpath, "-1");
rc = 4;
goto exit;
};
set_loading(udev, loadpath, "0");
Additionally, many devices use an Intel HEX format (textish files containing checksum and other stuff) (wiki it i have no reputation and no ability to link). The kernel program ihex2fw (called from Makefile in kernel_source/lib/firmware on .HEX files) converts these HEX files to an arbitrary-designed binary format that the Linux kernel then picks up with request_ihex_firmware
, because they thought reading text files in the kernel was silly (it would slow things down).
Solution 3:
On current Linux systems, this is handled via udev
and the firmware.agent
.
Solution 4:
Linux 3.5.7 Gentoo, I have the same issue. SOLVED:
emerge ipw2200-firmware
Then go to /usr/src/linux
make menucofig
on device driver, remove all wirless drivers don't needed, set Intell 2200 as module and recompile.
make
make modules_install
cp arch/x86/boot/bzImage /boot/kernel-yourdefault