2009-06-04 135 views
44

我在Ubuntu下编译一个定制的内核,我遇到了我的内核似乎不知道在哪里寻找固件的问题。在Ubuntu 8.04下,固件与驱动程序模块的内核版本相同。例如,内核2.6.24-24泛型存储其在内核模块:Linux内核如何知道在哪里查找驱动程序固件?

/lib/modules/2.6.24-24-generic 

及其在固件:

/lib/firmware/2.6.24-24-generic 

当我编译根据2.6.24-24泛型Ubuntu的内核“Alternate Build Method: The Old-Fashioned Debian Way”我得到适当的模块目录和我的所有设备都可以工作,除了那些需要我的英特尔无线网卡(ipw2200模块)等固件的设备。

内核日志显示例如,当IPW2200尝试加载固件内核子系统控制固件的装载无法找到它:

ipw2200: Detected Intel PRO/Wireless 2200BG Network Connection 
ipw2200: ipw2200-bss.fw request_firmware failed: Reason -2 

错误号-base.h此定义为:

#define ENOENT  2 /* No such file or directory */ 

(返回ENOENT功能使负在它的前面。)

我试图创建在/ lib /固件符号链接在我的内核的名字指出到2.6.24-24通用目录,但是这导致了相同的错误。此固件是非GPL,由英特尔提供并由Ubuntu打包。我不相信它与特定的内核版本有任何实际的联系。 cmp显示各个目录中的版本是相同的。

那么内核如何知道在哪里寻找固件?

更新

我发现this solution到我有确切的问题,但它不再工作作为Ubuntu已经消除/etc/hotplug.d,不再存储其固件/usr/lib/hotplug/firmware

UPDATE2

一些更多的研究打开了一些答案。直到版本92的udev,程序firmware_helper是固件加载的方式。从udev 93开始,这个程序被替换为一个名为firmware.sh的脚本,据我所知可以提供相同的功能。这两个硬件将固件路径硬编码为/lib/firmware。 Ubuntu似乎仍在使用/lib/udev/firmware_helper二进制文件。

固件文件的名称被传递到firmware_helper其中级联到路径/lib/firmware和用于加载固件环境变量$FIRMWARE

request_firmware(..., "ipw2200-bss.fw", ...); 

现在,在驱动程序调用request_firmwarefirmware_helper介于看$FIRMWARE环境变量:

实际的请求加载固件由驱动程序(IPW2200在我的情况),通过系统调用由,内核软件包名称会被预先固定到固件名称。

那么,谁在做呢?

+0

有人可以添加一条评论,解释他们为什么要投票关闭这个问题吗?我会很感激反馈。 – 2009-06-04 13:44:20

+2

由于它“属于serverfault.com”,因此被投票结束。由于这个问题不是关于编程,而更多是关于行政管理,这符合两个网站的使命陈述。 – ephemient 2009-06-04 22:21:59

+0

感谢您的反馈。我曾考虑过这是一个编程问题,因为这是在尝试构建定制内核时遇到的问题。我想知道为什么具体的人会认为这不是编程相关的,但我认为我有一些很好的猜测原因。 – 2009-06-05 14:18:55

回答

38

从内核的角度看,见/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. 

内核实际上并没有加载任何固件的。它只是通知用户空间,“我想要一个名为xxx的固件”,并等待用户空间将固件镜像传回内核。

现在,在Ubuntu 8.04,

 
$ grep firmware /etc/udev/rules.d/80-program.rules 
# Load firmware on demand 
SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware_helper" 

所以你已经发现,udev被配置为运行firmware_helper当内核请求固件。

 
$ 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 

如果你读了源,你会发现,Ubuntu的写了firmware_helper这是硬编码为先来说一下/lib/modules/$(uname -r)/$FIRMWARE,然后/lib/modules/$FIRMWARE,并没有其他的位置。将其转换成sh,它大致这样:

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 

这正是内核期望的格式。


为了使长话短说:Ubuntu的udev包具有自定义总是看在/lib/firmware/$(uname -r)第一。此政策正在用户空间中处理。

1

在当前的Linux系统上,这是通过udevfirmware.agent处理的。

+0

显然,Ubuntu 8.04在udev中没有firmware.agent,它有别的名字叫做firmware_helper。无论如何,这是如何告诉内核在哪里找到固件? – 2009-06-04 13:02:00

11

哇这是非常有用的信息,它导致我为需要固件的设备定制USB内核模块时出现问题的解决方案。

基本上,每个Ubuntu都会为hal,sysfs,devfs,udev等等带来新的变化......事情就会改变。事实上,我读到他们停止使用hal。

因此,我们再次反向工程,以便与最新的[Ubuntu]系统相关。

在Ubuntu Lucid(最新撰写本文时),使用了/lib/udev/rules.d/50-firmware.rules。该文件调用发生魔法的二进制文件/lib/udev/firmware

列表:/lib/udev/rules.d/50-firmware。规则

# firmware-class requests, copies files into the kernel 
SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware --firmware=$env{FIRMWARE} --devpath=$env{DEVPATH}" 

魔术应该是沿着这些路线的东西(来源:Linux Device Drivers, 3rd Ed., Ch. 14: The Linux Device Model):

  • 回声1至loading
  • 拷贝固件data
  • 失败,回声-1 loading并暂停固件加载过程
  • echo 0至loading(信号的内核)
  • 然后,一个特定的内核模块接收到的数据并将其推到设备

如果你看一下udev的Lucid的源页面,在udev-151/extras/firmware/firmware.c,源对于固件/ lib中/的udev /固件二进制文件,这正是如此。

摘录:清醒源,的udev-151 /额外/固件/ 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"); 

另外,许多设备使用Intel HEX格式(含有校验和其他东西textish文件)(维基它我有没有声望,也没有能力链接)。内核程序ihex2fw(在Makefile中调用kernel_source/lib/firmware.HEX文件)将这些HEX文件转换为任意设计的二进制格式,然后Linux内核使用request_ihex_firmware,因为他们认为读取内核中的文本文件时愚蠢(这会减慢速度)。

1

Linux 3.5.7 Gentoo,我有同样的问题。 解决:

emerge ipw2200-firmware 

然后去上的设备驱动程序的/ usr/src/linux中

make menucofig 

,删除不所需的所有驱动程序可无线上网,集INTELL 2200模块和重新编译。

make 
make modules_install 
cp arch/x86/boot/bzImage /boot/kernel-yourdefault