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, , , "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 ------ 字符设备驱动 之 “ 创建设备节点流程 ”的更多相关文章
- 字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联
转载自:http://www.kancloud.cn/yueqian_scut/emlinux/106829 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sy ...
- [kernel]字符设备驱动、平台设备驱动、设备驱动模型、sysfs几者之间的比较和关联
转自:http://www.2cto.com/kf/201510/444943.html Linux驱动开发经验总结,绝对干货! 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动 ...
- Linux 设备驱动开发 —— platform设备驱动应用实例解析
前面我们已经学习了platform设备的理论知识Linux 设备驱动开发 —— platform 设备驱动 ,下面将通过一个实例来深入我们的学习. 一.platform 驱动的工作过程 platfor ...
- linux驱动之设备号与创建设备节点
设备号: 1.自己主动分配 major = register_chrdev(0,"first_drv",&first_sdv_fops);//注冊 注冊设备时给设备号写0, ...
- 乾坤合一~Linux设备驱动之块设备驱动
1. 题外话 在蜕变成蝶的一系列学习当中,我们已经掌握了大部分Linux驱动的知识,在乾坤合一的分享当中,以综合实例为主要讲解,在一个月的蜕茧成蝶的学习探索当中,觉得数据结构,指针,链表等等占据了代码 ...
- 蜕变成蝶~Linux设备驱动之watchdog设备驱动
看门狗(watchdog )分硬件看门狗和软件看门狗.硬件看门狗是利用一个定时器 电路,其定时输出连接到电路的复位端,程序在一定时间范围内对定时器清零 (俗称 “喂狗”),如果程序出现故障,不在定时周 ...
- 蜕变成蝶~Linux设备驱动之按键设备驱动
在上述的驱动系列博客中,我们已经了解了关于阻塞和非阻塞.异步通知.轮询.内存和I/O口访问.并发控制等知识,按键设备驱动相对来说是比较简单的,本章内容可以加深我们对字符设备驱动架构.阻塞与非阻塞.中断 ...
- Linux 内核驱动自动创建设备节点并挂载设备
*注:本文来自http://blog.csdn.net/lwj103862095/article/details/17470573 一.首先需要在最开始定义两个数据结构: static struct ...
- linux driver ------ platform模型,通过杂项设备(主设备号是10)注册设备节点
注册完设备和驱动之后,就需要注册设备节点 Linux杂项设备出现的意义在于:有很多简单的外围字符设备,它们功能相对简单,一个设备占用一个主设备号对于内核资源来说太浪费.所以对于这些简单的字符设备它们共 ...
随机推荐
- How to RAMDISK on macOS
diskutil erasevolume HFS+ 'RAM Disk' `hdiutil attach -nomount ram://8388608`
- CML\LVDS
LVDS和CML电平应用区别 https://wenku.baidu.com/view/6bb0066f011ca300a6c3908c.html
- Multi-Targeting and Porting a .NET Library to .NET Core 2.0
Creating a new .NET Standard Project The first step for moving this library is to create a new .NET ...
- 第五十五天 css基础入门
一.引入css的三种方式 1.行间式 <div style="width: 100px; height: 100px; background-color: red">& ...
- P1216 数字三角形
题目描述 观察下面的数字金字塔. 写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大.每一步可以走到左下方的点也可以到达右下方的点. 7 3 8 8 1 0 2 7 4 4 4 5 ...
- I - Tunnel Warfare HDU - 1540 线段树最大连续区间
题意 :一段区间 操作1 切断点 操作2 恢复最近切断的一个点 操作3 单点查询该点所在最大连续区间 思路: 主要是push_up : 设区间x 为母区间 x<<1 ,x< ...
- 杨辉三角(java实现)
package lizi; import java.util.Scanner; public class Yanghui { private static Scanner input; public ...
- kubernetes(一)
•Kubernetes介绍 1.背景介绍 云计算飞速发展 - IaaS - PaaS - SaaS Docker技术突飞猛进 - 一次构建,到处运行 - 容器的快速轻量 - 完整的生态环境 2.什 ...
- 洛谷P4782 2-SAT问题
2-SAT问题 这是一道2-SAT的模板题.对于2-SAT问题的每一个条件,我们需要把他们转化成可接受的条件.即"若变量A的赋值为x,则变量B的赋值为y",其中x,y均等于0或1. ...
- POJ 3667 Hotel(算竞进阶习题)
线段树区间染色 题目要求最大的连续段的左端点,我们在查询的时候返回最左端即可,注意查找顺序,应该从左到右!! 另外这类染色的push_down其实比较简单,直接染成上一层的标记即可 push_up和连 ...