udev嵌入式上路经历
改编自udev轻松上路
第一、什么是udev?
这篇文章
UDEV Primer给我们娓娓道来,花点时间预习一下是值得的。
第二、为什么udev要取代devfs?
udev是硬件平台无关的,属于user space的进程,它脱离驱动层的关联而建立在操作系统之上,基于这种设计实现,我们可以随时修改及删除/dev下的设备文件名称和指向,随心所欲地按照我们的愿望安排和管理设备文件系统,而完成如此灵活的功能只需要简单地修改udev的配置文件即可,无需重新启动操作系统。udev
已经使得我们对设备的管理如探囊取物般轻松自如。
第三、如何得到udev?
udev的主页在这里:
http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html 我们按照下面的步骤来生成udev的工具程序,以arm-linux为例:
1、wget
http://www.us.kernel.org/pub/linux/utils/kernel/hotplug/udev-100.tar.bz2 2、tar xjf udev-100.tar.bz2
3、cd udev-100 编辑Makefile,查找CROSS_COMPILE,修改CROSS_COMPILE ?= arm-linux-
4、make
没有什么意外的话当前目录下生成udev,udevcontrol,udevd,udevinfo,udevmonitor,udevsettle,udevstart,
udevtest,udevtrigger九个工具程序,在嵌入式系统里,我们只需要udevd和udevstart就能使udev工作得很好,
其他工具则帮助我们完成udev的信息察看、事件捕捉或者更高级的操作。
另外一个方法是直接使用debian提供的已编译好的二进制包,美中不足的是版本老了一些。
1、wget
http://ftp.us.debian.org/debian/pool/main/u/udev/udev_0.056-3_arm.deb 2、ar -xf udev_0.056-3_arm.deb
3、tar xzf data.tar.gz
在sbin目录里就有我们需要的udevd和udevstart工具程序。
建议大家采用第一种方式生成的udevd和udevstart。
第四、如何配置udev?
首先,udev需要内核sysfs和tmpfs的支持,sysfs为udev提供设备入口和uevent通道,tmpfs为udev设备文件提供存放空间,也就是说,在上电之前系统上是没有足够的设备文件可用的,我们需要一些技巧让kernel先引导起来。
由于在kernel启动未完成以前我们的设备文件不可用,如果使用mtd设备作为rootfs的挂载点,这个时候/dev/mtdblock 是不存在的,我们无法让kernel找到rootfs,kernel只好停在那里惊慌。
这个问题我们可以通过给kernel传递设备号的方式来解决,在linux系统中,mtdblock的主设备号是31,part号从0开始,那么以前的/dev/mtdblock/3就等同于31:03,以次类推,所以我们只需要修改bootloader传给kernel 的cmd line参数,使root=31:03,就可以让kernel在udevd未起来之前成功的找到rootfs。
O.K.下一个问题。
其次,需要做的工作就是重新生成rootfs,把udevd和udevstart复制到/sbin目录。然后我们需要在/etc/下为udev
建立设备规则,这可以说是udev最为复杂的一步。这篇文章提供了最完整的指导:
Writing udev rules 文中描述的复杂规则我们可以暂时不用去理会,上路指南将带领我们轻松穿过这片迷雾。这里提供一个由简入繁的方法,对于嵌入式系统,这样做可以一劳永逸。
1、在rootfs/etc/udev下建立一个rules.d目录,生成一个空的配置文件
touch etc/udev/rules.d/udev.rules
2、vi etc/udev/udev.conf
###############################################
# vc devices
KERNEL=="tty[0-9]*", NAME="vc/%n"
# block devices
KERNEL=="loop[0-9]*", NAME="loop/%n"
# mtd devices
KERNEL=="mtd[0-9]*", NAME="mtd/%n"
KERNEL=="mtdblock*", NAME="mtdblock/%n"
# input devices
KERNEL=="mice" NAME="input/%k"
KERNEL=="mouse[0-9]*", NAME="input/%k"
KERNEL=="ts[0-9]*", NAME="input/%k"
KERNEL=="event[0-9]*", NAME="input/%k"
# misc devices
KERNEL=="apm_bios", NAME="misc/%k"
KERNEL=="rtc", NAME="misc/%k"
################################################
保存它,我们的设备文件系统基本上就可以了,udevd和udevstart会自动分析这个文件。
3、为了使udevd在kernel起来后能够自动运行,我们在rootfs/etc/init.d/rcS中增加以下几行:
##################################
/bin/mount -t sysfs sysfs /sys
/bin/mount -t tmpfs tmpfs /dev
echo "Starting udevd..."
/sbin/udevd --daemon
/sbin/udevstart
##################################
4、重新生成rootfs,烧写到flash指定的rootfs part中。
5、如果需要动态改变设备规则,可以把etc/udev放到jffs或yaffs part,以备修改,根据需求而定,可以随时扩
充udev.conf中的配置项。
参考资料:
http://www.reactivated.net/writing_udev_rules.html
http://webpages.charter.net/decibelshelp/LinuxHelp_UDEVPrimer.html#udevrules
http://www.die.net/doc/linux/man/man8/udev.8.html
udev-FAQ 中文翻译
原文出处 http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev-FAQ
中文翻译 王旭 http://gnawux.blogchina.com
本文档遵循 GPL 2 及以后版本发布,修改、发布请保持许可证不变
问: udev是什么? 它的目的何在?
答: 看看那篇 OLS 2003 上的有关 udev 的文章吧,可以在 docs 目录里找到,也能在这
里找到:
OLS 2003 上还有一个关于 udev 的幻灯片,可以在这里找到:
问: udev 和 devfs 是什么关系
答: udev 完全在用户态 (userspace) 工作,利用设备加入或移除时内核所发送的
hotplug 事件 (event) 来工作。关于设备的详细信息是由内核输出 (export) 到位
于 /sys 的 sysfs 文件系统的。所有的设备命名策略、权限控制和事件处理都是在
用户态下完成的。与此相反,devfs 是作为内核的一部分工作的。
问: 如果 udev 不能完成所有 devfs 的工作的话,为什么把 devfs 标记为
OBSOLETE/removed?
答: 引用 Al Viro (Linux VFS 内核维护者):
- devfs 所做的工作被确信可以在用户态来完成。
- devfs 被加入内核之时,大家寄望它的质量可以迎头赶上。
- devfs 被发现了一些可修复和无法修复的 bug。
- 对于可修复的 bug,几个月前就已经被修复了,其维护者认为一切良好。
- 对于后者,同样是相当常一段时间以来没有改观了。
- devfs 的维护者和作者对它感到失望并且已经停止了对代码的维护工作。
问: 但是当一个并不存在的 /dev 节点被打开的时候,udev 并不能如 devfs 一样自动加
载驱动程序。
答: 的确如此,但 Linux 的设计是在设备被发现的时候加载模块,而不是当它被访问的时
候。
问: 不过等等,我确实希望 udev 可以在不存在的节点被打开的时候自动加载驱动。这是
我使用 devfs 的唯一原因了。给 udev 增加这个功能吧。
答: 不,udev 是用来管理 /dev 的,不是用来加载内核驱动的。
问: 嗨,求你们了。这不难做到的。
答: 这么个功能对于一个配置正确的计算机是多余的。系统中所有的设备都应该产生
hotplug 事件、加载恰当的驱动,而 udev 将会注意到这点并且为它创建对应的
设备节点。如果你不想让所有的设备驱动停留在内存之中,应该使用其它东西来
管理你的模块 (如脚本, modules.conf, 等等) 这不是 udev 的工作。
问: 但是我真的喜欢那个功能,还是加上吧
答: devfs 用的方法导致了大量无用的 modprobe 尝试,以此程序探测设备是否存在。
每个试探性探测都新建一个运行 modprobe 的进程,而几乎所有这些都是无用的。
问: 我喜欢 devfs 的设备文件命名方式,udev 可以这样命名么?
答: 可以,udev 可以使用 /dev 的命名策略来创建节点。通过一个配置文件,可以把内
核缺省的名字映射到 devfs 的名字。可以看看 udev 中带的 udev.rules.devfs 文
件。
注意: devfs 的命名方式是不被建议并且不被官方支持的,因为它所用的简单枚举设
备的方式在设备可能被随时加入或删除的情况下确实是一个比较笨的方法。这些编号
代给你的将只有麻烦,而并不能用来确定设备。看看那个永久性磁盘 (persistent
disk) 的规则就知道如何在用户态下正确的做这件事,而不是傻傻地列出设备。
问: udev 可以为哪些设备创建节点?
答: 所有在 sysfs 中显示的设备都可以由 udev 来创建节点。如果内核中增加了其它设
备的支持,udev 也就自动地可以为它们工作了。现在所有的块设备都在被支持之列,
大部分的主字符设备也是被支持的。内核开发者们正致力于让所有的字符设备都被支
持。可以到 linux-kernel 邮件列表上寻找补丁或是查看补丁的状态。
问: udev 是否会去掉匿名设备数量的限制?
答: udev 完全工作于用户态。如果内核支持了更多的匿名设备,udev 就会支持。
问: udev 是否会支持符号链接?
答: udev 现在就支持符号链接,每个设备节点拥有多个符号链接也是被支持的。
问: udev 如何处理 /dev 文件系统?
答: 建议使用一个每次启动系统的时候重新创建的 tmpfs 作为 /dev 的文件系统。不过
实际上 udev 并不关心那种文件系统在被使用。
问: 在 init 运行之前,udev 如何处理设备?
答: udev 可以被放入 initramfs 之中,并在每个设备被发现的时候运行。也可以让
udev 工作在一个真的根分区被加载之后根据 /sys 的内容创建的初始 /dev 目录
之中。
问: 我是否可以利用 udev 在一个 USB 设备被加载的时候自动加载上这个设备?
答: 技术上讲是可以的,但是 udev 不是用于这个工作的。所有的主流发布版 (distro)
都包含了 HAL (http://freedesktop.org/wiki/Software_2fhal) 用于这个工作,它
也是专门用于监视设备变更的,并且集成进入了桌面软件。
换个角度说,这可以简单的通过 fstab 来实现:
/dev/disk/by-label/PENDRIVE /media/PENDRIVE vfat user,noauto 0 0
这样,用户可以用如下命令来访问设备:
$mount /media/PENDRIVE
同样不需要管理员权限,但却拥有了设备的全部访问权限。使用永久性磁盘链接
(label, uuid) 将可以指定同一设备,无论其实际上的内核名字是什么。
问: 有什么我需要注意的安全问题么?
答: 当使用动态设备编号的时候,一个给定的主/从设备号可能在不同时间对应不同的设
备,如果一个用户拥有对这个节点的访问权限,并且可以创建一个到这个节点的硬链
接,他就可以如此得到一个这个设备节点的拷贝。当设备被移除之后,udev 删除了
设备节点,但硬链接依然存在。如果这个设备节点之后被重新使用不同的访问权限被
创建的时候,其硬链接仍然可以使用先前的访问权限来访问。
(同样的问题也存在在使用 PAM 改变访问权限的 login 上。)
简单的解决方案就是通过把 /dev 放在 tmpfs 这样的单独的文件系统之上来防止建
立硬链接。
问: 我有其他的关于 udev 的问题,我应该问谁?
答: linux-hotplug-devel 正是问这些的地方。邮件列表的地址是
linux-hotplug-devel@lists.sourceforge.net
加入邮件列表的相关信息可以在如下地址找到