zoukankan      html  css  js  c++  java
  • linux driver ------ 字符设备驱动 之 “ 创建设备节点流程 ”

    在字符设备驱动开发的入门教程中,最常见的就是用device_create()函数来创建设备节点了,但是在之后阅读内核源码的过程中却很少见device_create()的踪影了,取而代之的是device_register()与device_add(),将device_create()函数展开不难发现:其实device_create()只是device_register()的封装,而device_register()则是device_add()的封装。

    struct device *device_create(struct class *class, struct device *parent,
                     dev_t devt, void *drvdata, const char *fmt, ...)
    {
        ......
        dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
        ......
        return dev;
    }
    struct device *device_create_vargs(struct class *class, struct device *parent,
                       dev_t devt, void *drvdata, const char *fmt,
                       va_list args)
    {
        ......
    
        dev->devt = devt;
        dev->class = class;
        dev->parent = parent;
        dev->release = device_create_release;
        dev_set_drvdata(dev, drvdata);
        ......
        retval = device_register(dev);
        ......
    }
    int device_register(struct device *dev)
    {
        device_initialize(dev);
        return device_add(dev);
    }

    加载驱动,执行device_add()函数,device_add()会在/sys目录对应设备目录下创建uevent属性节点,应用层的udev则会根据uevent来创建/dev目录下的设备节点,这里关于udev的部分不再赘述,我们继续分析device_create()、device_register()、device_add()三个函数在实际运用中的区别。 以一个简单的led设备字符设备驱动为例,下面分别用device_create()、device_register()、device_add()三个函数来创建设备节点“/dev/led”:

    1. device_create()

    static class *led_class;
    
    static int __init led_init(void)
    {
        int ret;
        dev_t devno;
        struct cdev *cdev;
        struct dev *dev;
    
        /* 注册设备号 */
        ret = alloc_chrdev_region(&devno, 0, 1, "led");
        if (ret < 0) 
            return ret;
    
        /* 分配、初始化、注册cdev*/
        cdev = cdev_alloc();
        if (IS_ERR(cdev)) {
            ret = PTR_ERR(cdev);
            goto out_unregister_devno;
        }
        cdev_init(&cdev, &led_fops);
        cdev.owner = THIS_MODULE;
        ret = cdev_add(&cdev, devno, 1);    
        if (ret) 
            goto out_free_cdev;
    
        /* 创建设备类 */
        led_class = class_create(THIS_MODULE, "led_class");
        if (IS_ERR(led_class)) {
            ret = PTR_ERR(led_class);
            goto out_unregister_cdev;
        } 
    
        /* 创建设备节点 */
        dev = device_create(led_class, NULL, devno, NULL, "led");
        if (IS_ERR(dev)) {
            ret = PTR_ERR(dev);
            goto out_del_class;
        }
    
        return 0;
    
    out_del_class:
        class_destroy(c78x_class); 
    out_unregister_cdev:
        cdev_del(cdev);
    out_free_cdev:
        kfree(cdev);
    out_unregister_devno:
        unregister_chrdev_region(devno, 1);
    
        return ret;
    }
    
    module_init(led_init);

    2. device_register()

    static class *led_class;
    
    static int __init led_init(void)
    {
        ......
    
         /* 注册设备号 */
        ......
        /* 分配、初始化、注册cdev*/
        ......
        /* 创建设备类 */
        ......
    
        /* 创建设备节点 */
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev) {
            ret = -ENOMEM;
            goto out_del_class;
        }
    
        dev->class = led_class;         // 关联设备类
        dev->parent = NULL;             
        dev->devt = devno;              // 关联设备号
        dev_set_drvdata(dev, NULL);     
        dev_set_name(dev, "led");       // 设置节点名字
        dev->release = device_create_release;
    
        ret = device_register(dev);
        if (ret) 
            goto out_put_dev;
    
        return 0;
    
    out_put_dev:
        put_device(dev);
        kree(dev);
    out_del_class:
        class_destroy(c78x_class);    
    out_unregister_cdev:    
        cdev_del(cdev);
    out_free_cdev:
        kfree(cdev);
    out_unregister_devno:
        unregister_chrdev_region(devno, 1);
    
        return ret;
    }
    
    module_init(led_init);

    3. device_add()

    static class *led_class;
    
    static int __init led_init(void)
    {
        ......
    
         /* 注册设备号 */
        ......
        /* 分配、初始化、注册cdev*/
        ......
        /* 创建设备类 */
        ......
    
        /* 创建设备节点 */
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev) {
            ret = -ENOMEM;
            goto out_del_class;
        }
    
        dev->class = led_class;         // 关联设备类
        dev->parent = NULL;             
        dev->devt = devno;              // 关联设备号
        dev_set_drvdata(dev, NULL);     
        dev_set_name(dev, "led");       // 设置节点名字
        dev->release = device_create_release;
    
        device_initialize(dev);
        ret = device_add(dev);
        if (ret) 
            goto out_put_dev;
    
        return 0;
    
    out_put_dev:
        put_device(dev);
        kree(dev);
    out_del_class:
        class_destroy(c78x_class);    
    out_unregister_cdev:    
        cdev_del(cdev);
    out_free_cdev:
        kfree(cdev);
    out_unregister_devno:
        unregister_chrdev_region(devno, 1);
    
        return ret;
    }
    
    module_init(led_init);
  • 相关阅读:
    python 数据结构与算法 day04 冒泡排序
    阿里代码扫描插件安装 (IDEA)
    Kafka
    女生赛训练 2
    2019 DISCS PrO High School Division
    计算机安全之密码安全 从 Hash 到 MD5
    CodeForces Round #559 Div.2
    CodeForces Round #558 Div.2
    CodeForces Round #560 Div.3
    NCD 2019 (AK)
  • 原文地址:https://www.cnblogs.com/god-of-death/p/10216103.html
Copyright © 2011-2022 走看看