Android和Linux下设备节点的创建笔记

1. Linux kernel创建的/dev/下的设备节点是不对的, 其实是kernel仅负责在/sys/(基于内存的虚拟文件系统)创建一大堆下目录和文件,而真正的设备节点是在用户空间程序创建的,应该是udev实现的。

2. 对于非android系统,应该是mdev,其实到底谁来处理,关键看kernel发送uevent事件,应用层通过什么方式处理的,是侦听socket还是通过设置/proc/sys/kernel/hotplug命令文件。

3. Android的设备节点和Linux的设备节点创建方式有些不同,但是都是通过捕获设备注册的event事件来创建设备节点的,而不是在device_add()里面就注册了,因为在内核启动阶段,根文件系统还没有挂载,没有/dev/目录。
在android系统中,由init进程负责处理这种uevent事件,如果是"add" device事件, init会在/dev/下创建相应的节点,具体代码可查看 system/core/init/devices.c: handle_device_event->make_device 节点的用户、组、权限都可以在devperms中定制。

Android 使用Init 进程来创建设备节点文件,分两种情况:静态节点文件和动态节点文件,以应对已经定义好的冷插拔和系统运行起来后插入的热插拔设备。
(1)对于冷插拔设备,init 进程事先获取等待冷插拔处理的驱动程序,事先定义好个驱动的设备节点文件(在android_source_code/system/core/init/devices.c中),在struct perms_devices[ ] 列出了设备节点的名称。访问权限,用户ID,组ID,若要添加新的用户定义的新设备需要在此结构体中添加相应信息。
(2)init 对于热插拔的动态设备,使用事件处理循环来完成,使用poll()监听来自驱动程序的uevent, 然后调用handle_device_fd()创建设备节点。

/*init.c中针对cold-plug设备节点的创建:*/
int main(int argc, char **argv)
int ueventd_main(int argc, char **argv)
device_init();
coldboot("/sys/class");
coldboot("/sys/block");
coldboot("/sys/devices");
do_coldboot(d); //他是一个递归函数
void handle_device_fd()
handle_device_event(&uevent);
handle_block_device_event(uevent);
handle_platform_device_event(uevent);
handle_generic_device_event(uevent); //在这个文件中创建设备节点
handle_device(uevent->action, devpath, uevent->path, , uevent->major, uevent->minor, links); static void handle_device(const char *action, const char *devpath, const char *path, int block, int major, int minor, char **links)
{
int i; if(!strcmp(action, "add")) {
make_device(devpath, path, block, major, minor, (const char **)links); /*创建设备节点*/
if (links) {
for (i = ; links[i]; i++)
make_link_init(devpath, links[i]);
}
} if(!strcmp(action, "remove")) {
if (links) {
for (i = ; links[i]; i++)
remove_link(devpath, links[i]); /*移除软链接*/
}
unlink(devpath); /*移除设备节点*/
} if (links) {
for (i = ; links[i]; i++)
free(links[i]);
free(links);
}
}
/*main.c中针对hot-plug设备的设备节点的创建*/
int main(int argc, char **argv)
{
.
.
. nr = poll(ufds, fd_count, timeout);
if (nr <= )
continue; for (i = ; i < fd_count; i++) {
if (ufds[i].revents & POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();
else if (ufds[i].fd == get_keychord_fd())
handle_keychord();
else if (ufds[i].fd == get_signal_fd())
handle_signal();
}
} return ;
}
上一篇:Linux设备驱动实现自己主动创建设备节点


下一篇:linux driver ------ 字符设备驱动 之 “ 创建设备节点流程 ”