您的位置:首页 > 运维架构 > Linux

Linux 字符设备驱动结构(二)—— 自动创建设备节点

2017-02-08 15:35 519 查看
上一篇我们介绍到创建设备文件的方法,利用cat /proc/devices查看申请到的设备名,设备号。
第一种是使用mknod手工创建:mknod filename type 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下寻找对应的类从而创建设备节点。

下面是两个函数的解析:

1、class_create(...) 函数

功能:创建一个类;

下面是具体定义:

[cpp]
view plain
copy





#define class_create(owner, name)       \  
({                      \  
    static struct lock_class_key __key; \  
    __class_create(owner, name, &__key);    \  
})  

owner:THIS_MODULE

name  : 名字


__class_create(owner, name, &__key)源代码如下:

[cpp]
view plain
copy





struct class *__class_create(struct module *owner, const char *name,  
                 struct lock_class_key *key)  
{  
    struct class *cls;  
    int retval;  
  
    cls = kzalloc(sizeof(*cls), GFP_KERNEL);  
    if (!cls) {  
        retval = -ENOMEM;  
        goto error;  
    }  
  
    cls->name = name;  
    cls->owner = owner;  
    cls->class_release = class_create_release;  
  
    retval = __class_register(cls, key);  
    if (retval)  
        goto error;  
  
    return cls;  
  
error:  
    kfree(cls);  
    return ERR_PTR(retval);  
}  
EXPORT_SYMBOL_GPL(__class_create);  

销毁函数:void class_destroy(struct class *cls)

[cpp]
view plain
copy





void class_destroy(struct class *cls)  
{  
    if ((cls == NULL) || (IS_ERR(cls)))  
        return;  
  
    class_unregister(cls);  
}  



2、device_create(...) 函数

struct device *device_create(struct class *class, struct device *parent,

                 dev_t devt, void *drvdata, const char *fmt, ...)


功能:创建一个字符设备文件

参数:

      struct class *class  :类
      struct device *parent:NULL
     dev_t devt  :设备号
     void *drvdata  :null、
     const char *fmt  :名字

返回:

    struct device *

下面是源码解析:

[cpp]
view plain
copy





struct device *device_create(struct class *class, struct device *parent,  
                 dev_t devt, void *drvdata, const char *fmt, ...)  
{  
    va_list vargs;  
    struct device *dev;  
  
    va_start(vargs, fmt);  
    dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);  
    va_end(vargs);  
    return dev;  
}  

device_create_vargs(class, parent, devt, drvdata, fmt, vargs)解析如下:

[cpp]
view plain
copy





struct device *device_create_vargs(struct class *class, struct device *parent,  
                   dev_t devt, void *drvdata, const char *fmt,  
                   va_list args)  
{  
    return device_create_groups_vargs(class, parent, devt, drvdata, NULL,  
                      fmt, args);  
}  

现在就不继续往下跟了,大家可以继续往下跟;

下面是一个实例:

hello.c

[cpp]
view plain
copy





#include <linux/module.h>  
#include <linux/fs.h>  
#include <linux/cdev.h>  
#include <linux/device.h>  
  
static int major = 250;  
static int minor=0;  
static dev_t devno;  
static struct class *cls;  
static struct device *test_device;  
  
static int hello_open (struct inode *inode, struct file *filep)  
{  
    printk("hello_open \n");  
    return 0;  
}  
static struct file_operations hello_ops=  
{  
    .open = hello_open,  
};  
  
static int hello_init(void)  
{  
    int ret;      
    printk("hello_init \n");  
  
  
    devno = MKDEV(major,minor);  
    ret = register_chrdev(major,"hello",&hello_ops);  
  
    cls = class_create(THIS_MODULE, "myclass");  
    if(IS_ERR(cls))  
    {  
        unregister_chrdev(major,"hello");  
        return -EBUSY;  
    }  
    test_device = device_create(cls,NULL,devno,NULL,"hello");//mknod /dev/hello  
    if(IS_ERR(test_device))  
    {  
        class_destroy(cls);  
        unregister_chrdev(major,"hello");  
        return -EBUSY;  
    }     
    return 0;  
}  
static void hello_exit(void)  
{  
    device_destroy(cls,devno);  
    class_destroy(cls);   
    unregister_chrdev(major,"hello");  
    printk("hello_exit \n");  
}  
MODULE_LICENSE("GPL");  
module_init(hello_init);  
module_exit(hello_exit);  

test.c

[cpp]
view plain
copy





#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <stdio.h>  
  
  
main()  
{  
    int fd;  
  
  
    fd = open("/dev/hello",O_RDWR);  
    if(fd<0)  
    {  
        perror("open fail \n");  
        return ;  
    }  
  
  
    close(fd);  
}  

makefile

[cpp]
view plain
copy





ifneq  ($(KERNELRELEASE),)  
obj-m:=hello.o  
$(info "2nd")  
else  
KDIR := /lib/modules/$(shell uname -r)/build  
PWD:=$(shell pwd)  
all:  
    $(info "1st")  
    make -C $(KDIR) M=$(PWD) modules  
clean:  
    rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order  
endif  

下面可以看几个class几个名字的对应关系:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: