• 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, 0, 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 = 0; links[i]; i++)
                    make_link_init(devpath, links[i]);
            }
        }
    
        if(!strcmp(action, "remove")) {
            if (links) {
                for (i = 0; links[i]; i++)
                    remove_link(devpath, links[i]); /*移除软链接*/
            }
            unlink(devpath); /*移除设备节点*/
        }
    
        if (links) {
            for (i = 0; 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 <= 0)
            continue;
    
        for (i = 0; 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 0;
    }
  • 相关阅读:
    error C2054: 在“inline”之后应输入“(”
    SendInput模拟键盘操作
    获取广电高清直播源
    Lua使用luasocket http请求例子
    枚举所有继承特定接口的类
    Stream Byte[] 转换
    async await
    C# ServiceStack.Redis 操作对象List
    resharper安装后,一不小心点错了(选择了object browser)
    fiddler 挂载 JS文件
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/10277639.html
Copyright © 2020-2023  润新知