本文共 2625 字,大约阅读时间需要 8 分钟。
驱动篇:udev 与 devfs(一)
尽管 devfs 有这样和那样的优点,但是,在 Linux 2.6 内核中, devfs 被认为是过时的方法,并最终被抛弃了, udev取代了它。 Linux VFS 内核维护者 Al Viro 指出了几点 udev 取代 devfs 的原因:
1 ) devfs 所做的工作被确信可以在用户态来完成。 2 ) devfs 被加入内核之时,大家期望它的质量可以迎头赶上。 3 )发现 devfs 有一些可修复和无法修复的 bug 。 4 )对于可修复的 bug ,几个月前就已经被修复了,其维护者认为一切良好。 5 )对于后者,在相当长的一段时间内没有改观。 6 ) devfs 的维护者和作者对它感到失望并且已经停止了对代码的维护工作。udev 完全在用户态工作,利用设备加入或移除时内核所发送的热插拔事件( Hotplug Event )来工作。在热插拔时,设备的详细信息会由内核通过 netlink 套接字发送出来,发出的事情叫 uevent 。 udev 的设备命名策略、权限控制和事件处理都是在用户态下完成的,它利用从内核收到的信息来进行创建设备文件节点等工作。下面给出了从内核通过 netlink 接收热插拔事件并冲刷掉的范例, udev 采用了类似的做法。
netlink 的使用范例:#includestatic void die(char *s) { write(2, s, strlen(s)); exit(1); } int main(int argc, char *argv[]){ struct sockaddr_nl nls; struct pollfd pfd; char buf[512]; // Open hotplug event netlink socket memset(&nls, 0, sizeof(struct sockaddr_nl)); nls.nl_family = AF_NETLINK; nls.nl_pid = getpid(); nls.nl_groups = -1; pfd.events = POLLIN; pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); if (pfd.fd == -1)die("Not root\n"); // Listen to netlink socket if (bind(pfd.fd, (void *)&nls, sizeof(struct sockaddr_nl)))die("Bind failed\n"); while (-1 != poll(&pfd, 1, -1)) { int i, len = recv(pfd.fd, buf, sizeof(buf), MSG_DONTWAIT); if (len == -1)die("recv\n"); // Print the data to stdout. i = 0; while (i < len) { printf("%s\n", buf + i); i += strlen(buf + i) + 1;} } die("poll\n"); // Dear gcc: shut up. return 0;}
编译上述程序并运行,把 Apple Facetime HD Camera USB 摄像头插入 Ubuntu ,该程序会 dump 类似如下的信息:
ACTION=add
DEVLINKS=/dev/input/by-id/usb-Apple_Inc.FaceTime_HD_Camera__Built-in_ CC2B2F0TLSDG6LL0-event-if00 /dev/input/by-path/pci-0000:00:0b.0-usb-0:1:1.0-event DEVNAME=/dev/input/event6 DEVPATH=/devices/pci0000:00/0000:00:0b.0/usb1/1-1/1-1:1.0/input/input6/event6 ID_BUS=usb ID_INPUT=1 ID_INPUT_KEY=1 ID_MODEL=FaceTime_HD_Camera__Built-in_ ID_MODEL_ENC=FaceTime\x20HD\x20Camera\x20\x28Built-in\x29 ID_MODEL_ID=8509 ID_PATH=pci-0000:00:0b.0-usb-0:1:1.0 ID_PATH_TAG=pci-
udev 就是采用这种方式接收 netlink 消息,并根据它的内容和用户设置给 udev 的规则做匹配来进行工作的。这里有一个问题,就是冷插拔的设备怎么办?冷插拔的设备在开机时就存在,在 udev 启动前已经被插入了。对于冷插拔的设备, Linux 内核提供了 sysfs 下面一个 uevent 节点,可以往该节点写一个 “add” ,导致内核重新发送 netlink ,之后 udev 就可以收到冷插拔的 netlink 消息了。我们还是运行上面的代码,并手动往 /sys/module/psmouse/uevent 写一个 “add” ,上述程序会 dump 出来这样的信息:
ACTION=add
DEVPATH=/module/psmouse SEQNUM=1682 SUBSYSTEM=module UDEV_LOG=3 USEC_INITIALIZED=220903546792
devfs 与 udev 的另一个显著区别在于:采用 devfs ,当一个并不存在的 /dev 节点被打开的时候, devfs 能自动加载对应的驱动,而 udev 则不这么做。这是因为 udev 的设计者认为 Linux 应该在设备被发现的时候加载驱动模块,而不是当它被访问的时候。 udev 的设计者认为 devfs 所提供的打开 /dev 节点时自动加载驱动的功能对一个配置正确的计算机来说是多余的。系统中所有的设备都应该产生热插拔事件并加载恰当的驱动,而 udev 能注意到这点并且为它创建对应的设备节点。
转载地址:https://blog.csdn.net/zytgg123456/article/details/110388503 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!