当用户向系统添加或删除设备时,内核会产生一个热插拔事件,并在/proc/sys/kernel/hotplug文件里查找处理设备连接的用户空间程序,这个用户空间程序主要有/sbin/hotplug与/sbin/mdev.
echo /sbin/hotplug > /proc/sys/kernel/hotplug
或者
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
hotplug
是一个bash脚本具有如下类似的代码:
1) 当driver执行kobject_uevent会调用hotplughelper,从而调用这个/sbin/hotplug脚本。
2) 该脚本在/etc/hotplug.d目录搜索所有以hotplug为后缀的程序并调用,
3) 传递给被调用的程序的参数就是事件的名字,
4) 被调用的程序还可以读取大量的环境变量,包括ACTION、DEVPATH、SUBSYSTEM等。
5) 被调用的程序根据这些环境变量在/lib/module/KERNEL_VERSION/modules.*map文件找到对应需要加载的模块并加载。
(*.map是当驱动程序使用MODULE_DEVICE_TABLE宏时,depmod程序使用这些信息并创建了/lib/module/KERNEL_VERSION/modules.*map文件。)
udev/mdev/vold
为用户空间提供使用固定设备名的动态/dev目录的解决办法。
mdev是简化的udev,是busybox所带的程序,适合嵌入式系统的使用。/sbin/mdev是一个链接,指向/bin/busybox
android系统中的vold机制与udev一样,android的源码NetlinkManager.cpp同样是监听基于netlink的套接字,并解析接收到的消息。
udev创建每个设备的名字和权限由/etc/udev/rules.d目录下的文件指定规则来设置,如果udev找不到所创建设备的权限文件,就将其缺省的权限设置为660,所有者root:root
热插拔设备
由于启动的时候运行了命令: echo /sbin/mdev > /proc/sys/kernel/hotplug,那么当有热插拔事件产生时,/sbin/mdev就会被调用,mdev根据环境变量中的ACTION和DEVPATH来确定此次热插拔事件的动作以及影响了/sys中的哪个目录,接着查看这个目录中是否有dev文件,如果有,就用这些信息在/dev目录下创建设备节点文件。
冷插拔设备
冷插拔的设备在开机时就存在,在udev启动前已经被插入了,对于冷插拔的设备,linux内核提供了sysfs下面的一个uevent节点,可以往该节点写入一个add,导致内核重新发送netlink,之后udev就可以收到冷插拔的netlink的消息了。
mdev -s
在/sys/class和/sys/block目录树中查找一个称为dev的文件,根据dev文件中记录的设备节点的主次设备号,从而在/dev目录下创建相应的设备节点。
/sys/bus/和/sys/class目录下的devices、drivers都是对/sys/devices目录下的文件的符号连接。
解决使用mdev时“cannot create /proc/sys/kernel/hotplug:nonexistent directory”错误
确保编译内核时编译如下选项:
CONFIG_PROC_FS=y
CONFIG_PROC_SYSCTL=y
CONFIG_HOTPLUG=y
CONFIG_NET=y
如果CONFIG_HOTPLUG和CONFIG_NET不选或没全选上的话,/proc/sys/kernel下将不会创建hotplug文件.(参见kernel/sysctl.c)
原理
上面device_create和device_register都可以用来添加struct device,其实在device_create中就是调用的device_register。
在kobject_uevent中既可以通过netlink向用户空间程序udevd发送uevent事件,也可以直接调用用户空间程序hotplug_helper
需要注意的是,
如果在device_add中dev_t = 0,则最后udevd不会在/dev目录下创建相应的设备节点
如果在device_add中dev_t != 0,则mdev或者hotplug根据dev中的内容(major:minor)来生成设备节点。
device_add是在/sys/devices/目录下添加设备,/sys/bus/和/sys/class目录下的devices、drivers都是对/sys/devices目录下的文件的符号连接。
Udev完全工作在用户态,利用设备加入或者移除时内核所发送的热插拔事件来工作
在热插拔的时候,设备的详细信息会由内核通过netlink套接字发送出来,发出来的事情叫做的uevent,udev的命名策略、权限控制和事件处理都是在用户态下完成的,他利用从内核收到的信息来创建设备文件节点等工作。
下面这段程序就是用来接收内核netlink发出来的信息,将设备插到系统中会打印从内核中接收到的信息。
Udev就是用这种方式接收netlink的消息,并根据他的内容和用户设置的udev的规则做匹配来进行工作的。
可以借助udev的工具udevadm info查找规则文件所能利用的内核信息和sysfs属性信息,
如运行”udevadm info -a -p /sys/devices/platform/serial8250/tty/ttyS0”
如果/dev目录下的节点已经被创建,但是不知道他对应的/sys/具体节点路径,
Udevadm info -q path -n /dev/节点名
参考文章:
1. Linux设备模型(热插拔、mdev 与 firmware)
2. mdev hotplug设备
3. Linux设备模型、sysfs文件系统与udev设备文件