Linux热插拔处理机制
一、 udev
在2.6内核里,使用了udev来取代hotplug。据udev的作者Greg K.H说,之所以废弃了hotplug原因是sysfs的出现,这个东西会产生非常多的hotplug事件,远远超过了2.4的内核(只要实现了了kobject模型的设备驱动都回产生该事件)。所以hotplug变得复杂,而且因为hotplug都是bash所写,所以开始变得没有效率。于是出现了一个名叫hotplug-ng的项目,就是为了解决这个过于复杂以及缺乏效率的问题,ng应该是next generation的意思。但这个项目目前为止还不能胜任角色,所以udev挺身而出,充当了救火队员。
2.6.15之后,/proc/sys/kernel/hotplug会成空的,因为内核通知用户空间的接口变成了netlink,所以最新的udev也采用了netlink接口去写,废弃了/sbin/hotplug或者/sbin/udevsend。udev在2.6.15以后的内核上可以直接通过netlink接听设备事件,sysfs提供了uevent文件,对该文件的“写”可以送出设备事件!
udev完全在用户态 (userspace)工作,利用设备加入或移除时内核所发送的hotplug事件 (event)来工作。关于设备的详细信息是由内核输出 (export)到位于 /sys的 sysfs文件系统的。所有的设备命名策略、权限控制和事件处理都是在用户态下完成的。与此相反,devfs是作为内核的一部分工作的。
传统上一般 Linux系统使用创建静态设备的方法,因此在 /dev目录下创建了大量的设备节点(有时会有数千个节点),而不管对应的硬件设备实际上是否存在。这通常是由 MAKEDEV 脚本完成的,这个脚本包含许多调用 mknod程序的命令,为这个世界上可能存在的每个设备创建相应的主设备号和次设备号。而使用 udev方式的时候,只有被内核检测到的设备才为其创建设备节点。因为每次系统启动的时候都要重新创建这些设备节点,所以它们被存储在 tmpfs文件系统上,设备节点不需要很多磁盘空间,所占用的内存可以忽略不计。
udev初始化脚本负责在 Linux启动的时候创建设备节点,该脚本首先将 /sbin/udevsend注册为热插拔事件处理程序。热插拔事件(随后将讨论)本不应该在这个阶段发生,注册 udev 只是为了以防万一。然后 udevstart遍历 /sys文件系统,并在 /dev目录下创建符合描述的设备。例如,/sys/class/tty/vcs/dev里含有"7:0"字符串,udevstart就根据这个字符串创建主设备号为 7、次设备号为 0的 /dev/vcs设备。udevstart创建的每个设备的名字和权限由 /etc/udev/rules.d/目录下的文件指定的规则来设置。如果 udev找不到所创建设备的权限文件,就将其权限设置为缺省的 660,所有者为 root:root。上面的步骤完成后,那些已经存在并且已经内建驱动的设备就可以使用了。
对于以模块驱动的设备,当内核检测到一个新设备连接时,内核会产生一个热插拔事件,并在 /proc/sys/kernel/hotplug文件里查找处理设备连接的用户空间程序(新的内核通知接口改变,/proc/sys/kernel/hotplug为空了)。udev
初始化脚本将udevsend
注册为该处理程序。当产生热插拔事件的时候,内核让 udev在 /sys文件系统里检测与新设备的有关信息,并为新设备在 /dev里创建项目。
所有在 sysfs中显示的设备都可以由 udev来创建节点。如果内核中增加了其它设备的支持,udev也就自动地可以为它们工作了。
大多数 Linux发行版通过 /etc/modules.conf配置文件来处理模块加载,对某个设备节点的访问导致相应的内核模块被加载。对 udev这个方法就行不通,因为在模块加载前,设备节点根本不存在。Linux的设计是在设备被发现的时候加载模块,而不是当它被访问的时候。通过在 /etc/sysconfig/modules文件里添加模块名,就可以在系统启动的时候加载这些模块,这样udev
就可以检测到设备,并创建相应的设备节点了。
如何写udev规则。通过udevinfo程序来找到那些可以作为规则文件里的匹配项的项目。分为两种情况:第一种情况是,当你把设备插入系统后,系统为设备产生了设备名(如/dev/sda)。那样的话,你先用udevinfo -q path -n /dev/sda,命令会产生一个该设备名对应的在sysfs下的路径,如/block/sda。然后,你再用udevinfo -a -p /sys/block/sda,这个命令会显示一堆信息,信息分成很多块。这些信息实际来自于操作系统维护的sysfs链表,不同的块对应不同的路径。你就可以用这些信息来作为udev规则文件中的匹配项。但需要注意的是,同一个规则只能使用同一块中显示的信息,不能跨块书写规则;第二种情况是,不知道系统产生的设备名,那就只有到/sys目录下去逐个目录查找了,反复用udevinfo -a -p /sys/path...这个命令看信息,如果对应的信息是这个设备的,那就恭喜你。否则就再换个目录。当然,在这种情况下,成功的可能性比较小。
二、 HAL
HAL位于设备驱动程序和应用程序之间。
三、 D-BUS
D-BUS是一个大有前途的消息总线和活动系统,正开始深入地渗透到 Linux桌面之中。D-BUS本质上是进程间通信(inter-process communication)(IPC)的一个实现,设计用于桌面应用程序和 OS 通信。
典型的 D-BUS设置将由几个总线构成。一个持久的系统总线(system bus),它在引导时就会启动。这个总线由操作系统和后台进程使用,安全性非常好,以使得任意的应用程序不能欺骗系统事件。还将有很多会话总线(session buses),这些总线当用户登录后启动,属于那个用户私有。
一个更为有趣但很不实用的例子是 Jamboree和 Ringaling的结合。Jamboree是一个简单的音乐播放器,它具有 D-BUS接口,以使得它可以被告知播放、到下一首歌、改变音量等等。Ringaling是一个小程序,它打开 /dev/ttyS0(一个串行端口)并观察接收到的内容。当 Ringaling 发现文本“RING”时,就通过 D-BUS 告知 Jamboree减小音量。最终的结果是,如果您的计算机上插入了一个调制解调器,而且电话铃响,则音乐音量就会为您减小。
这正是计算机所追求的!
四、 一些查看硬件信息的工具
lspci
列出所有PCI设备。有两个参数是比较常用,-b和-v,lspci也会把usb接口列出来。
lshal列出系统硬件设备。
Usbmodules
列出可用于已插入usb设备的驱动模块。