您的位置:首页 > 其它

device_create()、device_register()、deivce_add()区别

2017-06-28 15:00 429 查看
本文基于linux 3.10.40,其他版本仅供参考

在字符设备驱动开发的入门教程中,最常见的就是用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()会在/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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息