Linux设备文件自动生成
原文:https://www.cnblogs.com/chen-farsight/p/6154941.html
第一种是使用mknod手工创建:# mknod <devfilename> <devtype> <major> <minor>
第二种是自动创建设备节点:利用udev(mdev)来实现设备文件的自动创建,首先应保证支持udev(mdev),由busybox配置。
具体udev相关知识这里不详细阐述,可以移步Linux 文件系统与设备文件系统 —— udev 设备文件系统,这里主要讲使用方法。
在驱动用加入对udev 的支持主要做的就是:在驱动初始化的代码里调用class_create(...)为该设备创建一个class,再为每个设备调用device_create(...)创建对应的设备。
内核中定义的struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用 device_create(…)函数来在/dev目录下创建相应的设备节点。
这样,加载模块的时候,用户空间中的udev会自动响应 device_create()函数,去/sysfs下寻找对应的类从而创建设备节点。
下面是两个函数的解析:
支持字符设备文件自动生成
linux/device.h
struct class *class_create(struct module *owner, const char *name); /* 功能:在/sys/class目录下创建一个目录,目录名是name指定的 参数: struct module *owner - THIS_MODULE const char *name - 设备名 返回值: 成功:class指针 失败: - bool IS_ERR(const void *ptr) 判断是否出错 long PTR_ERR(const void *ptr) 转换错误码 */
void class_destroy(struct class *cls); /* 功能:删除class指针指向的目录 参数: struct class *cls - class指针 */
struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...); /* 功能: 在class指针指向的目录下再创建一个目录,目录名由const char *fmt, ...指出、并导出设备信息(dev_t) 参数: struct class *cls - class指针 struct device *parent - 父对象,NULL dev_t devt - 设备号 void *drvdata - 驱动私有数据 const char *fmt, ... - fmt是目录名字符串格式,...就是不定参数 返回值: 成功 - device指针 失败 - bool IS_ERR(const void *ptr) 判断是否出错 long PTR_ERR(const void *ptr) 转换错误码 */
void device_destroy(struct class *cls, dev_t devt); /* 功能:删除device_create创建的目录 参数: struct class *cls - class指针 dev_t devt - 设备号 */
创建次序
struct class *class_create(struct module *owner, const char *name);
struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
删除次序
void device_destroy(struct class *cls, dev_t devt);
void class_destroy(struct class *cls);
实例:
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/errno.h> #include <asm/current.h> #include <linux/sched.h> #include <linux/device.h> MODULE_LICENSE("GPL"); static struct class *cls = NULL; static int major = 0; static int minor = 0; const int count = 6; #define DEVNAME "demo" static struct cdev *demop = NULL; //打开设备 static int demo_open(struct inode *inode, struct file *filp) { //get command and pid printk(KERN_INFO "%s : %s : %d\n", __FILE__, __func__, __LINE__);return 0; } //关闭设备 static int demo_release(struct inode *inode, struct file *filp) { //get major and minor from inode printk(KERN_INFO "%s : %s : %d\n", __FILE__, __func__, __LINE__); return 0; } static struct file_operations fops = { .owner = THIS_MODULE, .open = demo_open, .release= demo_release, }; static int __init demo_init(void) { dev_t devnum; int ret, i; struct device *devp = NULL; //1. alloc cdev obj demop = cdev_alloc(); if(NULL == demop){ return -ENOMEM; } //2. init cdev obj cdev_init(demop, &fops); ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME); if(ret){ goto ERR_STEP; } major = MAJOR(devnum); //3. register cdev obj ret = cdev_add(demop, devnum, count); if(ret){ goto ERR_STEP1; } cls = class_create(THIS_MODULE, DEVNAME); if(IS_ERR(cls)){ ret = PTR_ERR(cls); goto ERR_STEP1; } for(i = minor; i < (count+minor); i++){ devp = device_create(cls, NULL, MKDEV(major, i), NULL, "%s%d", DEVNAME, i); if(IS_ERR(devp)){ ret = PTR_ERR(devp); goto ERR_STEP2; } } return 0; ERR_STEP2: for(--i; i >= minor; i--){ device_destroy(cls, MKDEV(major, i)); } class_destroy(cls); ERR_STEP1: unregister_chrdev_region(devnum, count); ERR_STEP: cdev_del(demop); //get command and pid printk(KERN_INFO "%s : %s : %d - fail.\n", __FILE__, __func__, __LINE__); return ret; } static void __exit demo_exit(void) { int i; //get command and pid printk(KERN_INFO "%s : %s : %d - leave.\n", __FILE__, __func__, __LINE__); for(i=minor; i < (count+minor); i++){ device_destroy(cls, MKDEV(major, i)); } class_destroy(cls); unregister_chrdev_region(MKDEV(major, minor), count); cdev_del(demop); } module_init(demo_init); module_exit(demo_exit);
下面可以看几个class几个名字的对应关系:
相关文章
- linux驱动开发--字符设备:添加文件指针偏移的功能
- [Linux]linux如何把文件切成多块
- linux平台总线驱动设备模型之点亮LED
- Linux平台总线驱动设备模型
- Linux基础之linux服务器服务器间拷贝文件
- Qt音视频开发02-海康sdk解码(支持句柄/回调/GPU模式/支持win/linux)
- 【Linux 内核】编译 Linux 内核 ② ( 解压内核源码 | 查询当前 Linux 内核版本号 | 进入并查看 linux 内核源码目录 )
- 【Linux】linux经常使用基本命令
- Linux I2C设备驱动编写(三)-实例分析AM3359
- L75.linux命令每日一练 -- 第11章 Linux系统管理命令 -- lsof和uptime
- L66.linux命令每日一练 -- 第十章 Linux网络管理命令 -- arp和ip
- L63.linux命令每日一练 -- 第九章 Linux进程管理命令 -- runlevel、init和service
- L43.linux命令每日一练 -- 第七章 Linux用户管理及用户信息查询命令 -- chage和chpasswd
- L34.linux命令每日一练 -- 第五章 Linux信息显示与搜索文件命令 -- echo和watch
- 嵌入式linux开发,Linux下访问PHY芯片寄存器,获取phyID号,获取phy的link状态
- 使用wget批量下载geo数据集的全部文件 linux下载geo数据 geo处理的数据不是下载原始数据 Linux如何下载ftp文件 geo ftp geo ftp下载 geo下载
- LINUX设备驱动程序的注意事项(两)建设和执行模块
- 周立功arm linux教程,极速搭建周立功IMX287A ARM Linux开发环境
- linux版本和目录结构
- 在 Linux 中强制卸载的 3 种方法显示“设备正忙”