在字符设备驱动开发的入门教程中,最常见的就是用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, , , "led");
if (ret < )
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, );
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 ; 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, ); 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 ; 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, ); 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 ; 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, ); return ret;
} module_init(led_init);

linux driver ------ 字符设备驱动 之 “ 创建设备节点流程 ”的更多相关文章

  1. 字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联

    转载自:http://www.kancloud.cn/yueqian_scut/emlinux/106829 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sy ...

  2. [kernel]字符设备驱动、平台设备驱动、设备驱动模型、sysfs几者之间的比较和关联

    转自:http://www.2cto.com/kf/201510/444943.html Linux驱动开发经验总结,绝对干货! 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动 ...

  3. Linux 设备驱动开发 —— platform设备驱动应用实例解析

    前面我们已经学习了platform设备的理论知识Linux 设备驱动开发 —— platform 设备驱动 ,下面将通过一个实例来深入我们的学习. 一.platform 驱动的工作过程 platfor ...

  4. linux驱动之设备号与创建设备节点

    设备号: 1.自己主动分配 major = register_chrdev(0,"first_drv",&first_sdv_fops);//注冊 注冊设备时给设备号写0, ...

  5. 乾坤合一~Linux设备驱动之块设备驱动

    1. 题外话 在蜕变成蝶的一系列学习当中,我们已经掌握了大部分Linux驱动的知识,在乾坤合一的分享当中,以综合实例为主要讲解,在一个月的蜕茧成蝶的学习探索当中,觉得数据结构,指针,链表等等占据了代码 ...

  6. 蜕变成蝶~Linux设备驱动之watchdog设备驱动

    看门狗(watchdog )分硬件看门狗和软件看门狗.硬件看门狗是利用一个定时器 电路,其定时输出连接到电路的复位端,程序在一定时间范围内对定时器清零 (俗称 “喂狗”),如果程序出现故障,不在定时周 ...

  7. 蜕变成蝶~Linux设备驱动之按键设备驱动

    在上述的驱动系列博客中,我们已经了解了关于阻塞和非阻塞.异步通知.轮询.内存和I/O口访问.并发控制等知识,按键设备驱动相对来说是比较简单的,本章内容可以加深我们对字符设备驱动架构.阻塞与非阻塞.中断 ...

  8. Linux 内核驱动自动创建设备节点并挂载设备

    *注:本文来自http://blog.csdn.net/lwj103862095/article/details/17470573 一.首先需要在最开始定义两个数据结构: static struct ...

  9. linux driver ------ platform模型,通过杂项设备(主设备号是10)注册设备节点

    注册完设备和驱动之后,就需要注册设备节点 Linux杂项设备出现的意义在于:有很多简单的外围字符设备,它们功能相对简单,一个设备占用一个主设备号对于内核资源来说太浪费.所以对于这些简单的字符设备它们共 ...

随机推荐

  1. MySQL 5.7 关闭严格模式

    If your app was written for older versions of MySQL and is not compatible with strict SQL mode in My ...

  2. webpack配置之代码优化

    前面的话 前面介绍了webpack的基本配置,本文将详细介绍webpack中关于代码优化的配置 打包公共代码 CommonsChunkPlugin 插件,是一个可选的用于建立一个独立文件(又称作 ch ...

  3. Spring 使用介绍(五)—— AOP(一)

    一.简单使用:Hello World实例 1.定义目标类 public interface Hello { void sayHello(); } public class HelloImpl impl ...

  4. python 模块之-time

    python 模块time import time # 1 time() :返回当前时间的时间戳 time.time() #1473525444.037215 #------------------- ...

  5. springboot 学习

    参考:http://www.cnblogs.com/sam-uncle/p/8796212.html spring boot 系列之一:spring boot 入门 注意:main启动类和contro ...

  6. BZOJ4818 [SDOI2017] 序列计数 【矩阵快速幂】

    题目分析: 一个很显然的同类项合并.注意到p的大小最大为100,考虑把模p意义下相同的求出来最后所有的减去没有质数的做矩阵快速幂即可. 代码: #include<bits/stdc++.h> ...

  7. [ZJOI2007] 仓库建设

    传送门:>HERE< 题意:有n个地点,每个地点有货物P[i]个,距离起点(地点0)的距离为x[i].在每个地点建立仓库需要费用c[i],现在需要在某些地点建设仓库,从而将货物转移到仓库里 ...

  8. 网络流相关知识点以及题目//POJ1273 POJ 3436 POJ2112 POJ 1149

    首先来认识一下网络流中最大流的问题 给定一个有向图G=(V,E),把图中的边看做成管道,边权看做成每根管道能通过的最大流量(容量),给定源点s和汇点t,在源点有一个水源,在汇点有一个蓄水池,问s-t的 ...

  9. python3 特性

    切片: 就是可以取到对象中任意位置的元素,[start:end:interval]:字符串.列表.元组可切片,字典.set()不可: L[:] #复制原L L[:10] #前十个 L[-10:] #后 ...

  10. [SPOJ375]QTREE - Query on a tree【树链剖分】

    题目描述 给你一棵树,两种操作. 修改边权,查找边权的最大值. 分析 我们都知道,树链剖分能够维护点权. 而且每一条边只有一个,且唯一对应一个儿子节点,那么就把信息放到这个儿子节点上. 注意,lca的 ...