码迷,mamicode.com
首页 > 系统相关 > 详细

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

时间:2019-01-03 19:34:46      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:封装   sys   加载驱动   des   stat   字符   drive   release   void   

在字符设备驱动开发的入门教程中,最常见的就是用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);

 

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

标签:封装   sys   加载驱动   des   stat   字符   drive   release   void   

原文地址:https://www.cnblogs.com/god-of-death/p/10216103.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!