Linux设备文件自动生成

原文链接:https://www.cnblogs.com/chen-farsight/p/6154941.html

第一种是使用mknod手工创建:# mknod

第二种是自动创建设备节点:利用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设备驱动开发

猜你喜欢

转载自blog.csdn.net/diezhongbing1358/article/details/85599228