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

上一篇我们介绍到创建设备文件的方法,利用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
  在CODE上查看代码片 派生到我的代码片
  1. #define class_create(owner, name)       \  
  2. ({                      \  
  3.     static struct lock_class_key __key; \  
  4.     __class_create(owner, name, &__key);    \  
  5. })  

owner:THIS_MODULE
name  : 名字

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

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. struct class *__class_create(struct module *owner, const char *name,  
  2.                  struct lock_class_key *key)  
  3. {  
  4.     struct class *cls;  
  5.     int retval;  
  6.   
  7.     cls = kzalloc(sizeof(*cls), GFP_KERNEL);  
  8.     if (!cls) {  
  9.         retval = -ENOMEM;  
  10.         goto error;  
  11.     }  
  12.   
  13.     cls->name = name;  
  14.     cls->owner = owner;  
  15.     cls->class_release = class_create_release;  
  16.   
  17.     retval = __class_register(cls, key);  
  18.     if (retval)  
  19.         goto error;  
  20.   
  21.     return cls;  
  22.   
  23. error:  
  24.     kfree(cls);  
  25.     return ERR_PTR(retval);  
  26. }  
  27. EXPORT_SYMBOL_GPL(__class_create);  

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

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void class_destroy(struct class *cls)  
  2. {  
  3.     if ((cls == NULL) || (IS_ERR(cls)))  
  4.         return;  
  5.   
  6.     class_unregister(cls);  
  7. }  


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
  在CODE上查看代码片 派生到我的代码片
  1. struct device *device_create(struct class *classstruct device *parent,  
  2.                  dev_t devt, void *drvdata, const char *fmt, ...)  
  3. {  
  4.     va_list vargs;  
  5.     struct device *dev;  
  6.   
  7.     va_start(vargs, fmt);  
  8.     dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);  
  9.     va_end(vargs);  
  10.     return dev;  
  11. }  

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

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. struct device *device_create_vargs(struct class *classstruct device *parent,  
  2.                    dev_t devt, void *drvdata, const char *fmt,  
  3.                    va_list args)  
  4. {  
  5.     return device_create_groups_vargs(class, parent, devt, drvdata, NULL,  
  6.                       fmt, args);  
  7. }  
现在就不继续往下跟了,大家可以继续往下跟;


下面是一个实例:

hello.c

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <linux/module.h>  
  2. #include <linux/fs.h>  
  3. #include <linux/cdev.h>  
  4. #include <linux/device.h>  
  5.   
  6. static int major = 250;  
  7. static int minor=0;  
  8. static dev_t devno;  
  9. static struct class *cls;  
  10. static struct device *test_device;  
  11.   
  12. static int hello_open (struct inode *inode, struct file *filep)  
  13. {  
  14.     printk("hello_open \n");  
  15.     return 0;  
  16. }  
  17. static struct file_operations hello_ops=  
  18. {  
  19.     .open = hello_open,  
  20. };  
  21.   
  22. static int hello_init(void)  
  23. {  
  24.     int ret;      
  25.     printk("hello_init \n");  
  26.   
  27.   
  28.     devno = MKDEV(major,minor);  
  29.     ret = register_chrdev(major,"hello",&hello_ops);  
  30.   
  31.     cls = class_create(THIS_MODULE, "myclass");  
  32.     if(IS_ERR(cls))  
  33.     {  
  34.         unregister_chrdev(major,"hello");  
  35.         return -EBUSY;  
  36.     }  
  37.     test_device = device_create(cls,NULL,devno,NULL,"hello");//mknod /dev/hello  
  38.     if(IS_ERR(test_device))  
  39.     {  
  40.         class_destroy(cls);  
  41.         unregister_chrdev(major,"hello");  
  42.         return -EBUSY;  
  43.     }     
  44.     return 0;  
  45. }  
  46. static void hello_exit(void)  
  47. {  
  48.     device_destroy(cls,devno);  
  49.     class_destroy(cls);   
  50.     unregister_chrdev(major,"hello");  
  51.     printk("hello_exit \n");  
  52. }  
  53. MODULE_LICENSE("GPL");  
  54. module_init(hello_init);  
  55. module_exit(hello_exit);  

test.c

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <sys/types.h>  
  2. #include <sys/stat.h>  
  3. #include <fcntl.h>  
  4. #include <stdio.h>  
  5.   
  6.   
  7. main()  
  8. {  
  9.     int fd;  
  10.   
  11.   
  12.     fd = open("/dev/hello",O_RDWR);  
  13.     if(fd<0)  
  14.     {  
  15.         perror("open fail \n");  
  16.         return ;  
  17.     }  
  18.   
  19.   
  20.     close(fd);  
  21. }  

makefile

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. ifneq  ($(KERNELRELEASE),)  
  2. obj-m:=hello.o  
  3. $(info "2nd")  
  4. else  
  5. KDIR := /lib/modules/$(shell uname -r)/build  
  6. PWD:=$(shell pwd)  
  7. all:  
  8.     $(info "1st")  
  9.     make -C $(KDIR) M=$(PWD) modules  
  10. clean:  
  11.     rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order  
  12. endif  

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




上一篇我们介绍到创建设备文件的方法,利用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
  在CODE上查看代码片 派生到我的代码片
  1. #define class_create(owner, name)       \  
  2. ({                      \  
  3.     static struct lock_class_key __key; \  
  4.     __class_create(owner, name, &__key);    \  
  5. })  

owner:THIS_MODULE
name  : 名字

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

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. struct class *__class_create(struct module *owner, const char *name,  
  2.                  struct lock_class_key *key)  
  3. {  
  4.     struct class *cls;  
  5.     int retval;  
  6.   
  7.     cls = kzalloc(sizeof(*cls), GFP_KERNEL);  
  8.     if (!cls) {  
  9.         retval = -ENOMEM;  
  10.         goto error;  
  11.     }  
  12.   
  13.     cls->name = name;  
  14.     cls->owner = owner;  
  15.     cls->class_release = class_create_release;  
  16.   
  17.     retval = __class_register(cls, key);  
  18.     if (retval)  
  19.         goto error;  
  20.   
  21.     return cls;  
  22.   
  23. error:  
  24.     kfree(cls);  
  25.     return ERR_PTR(retval);  
  26. }  
  27. EXPORT_SYMBOL_GPL(__class_create);  

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

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void class_destroy(struct class *cls)  
  2. {  
  3.     if ((cls == NULL) || (IS_ERR(cls)))  
  4.         return;  
  5.   
  6.     class_unregister(cls);  
  7. }  


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
  在CODE上查看代码片 派生到我的代码片
  1. struct device *device_create(struct class *classstruct device *parent,  
  2.                  dev_t devt, void *drvdata, const char *fmt, ...)  
  3. {  
  4.     va_list vargs;  
  5.     struct device *dev;  
  6.   
  7.     va_start(vargs, fmt);  
  8.     dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);  
  9.     va_end(vargs);  
  10.     return dev;  
  11. }  

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

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. struct device *device_create_vargs(struct class *classstruct device *parent,  
  2.                    dev_t devt, void *drvdata, const char *fmt,  
  3.                    va_list args)  
  4. {  
  5.     return device_create_groups_vargs(class, parent, devt, drvdata, NULL,  
  6.                       fmt, args);  
  7. }  
现在就不继续往下跟了,大家可以继续往下跟;


下面是一个实例:

hello.c

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <linux/module.h>  
  2. #include <linux/fs.h>  
  3. #include <linux/cdev.h>  
  4. #include <linux/device.h>  
  5.   
  6. static int major = 250;  
  7. static int minor=0;  
  8. static dev_t devno;  
  9. static struct class *cls;  
  10. static struct device *test_device;  
  11.   
  12. static int hello_open (struct inode *inode, struct file *filep)  
  13. {  
  14.     printk("hello_open \n");  
  15.     return 0;  
  16. }  
  17. static struct file_operations hello_ops=  
  18. {  
  19.     .open = hello_open,  
  20. };  
  21.   
  22. static int hello_init(void)  
  23. {  
  24.     int ret;      
  25.     printk("hello_init \n");  
  26.   
  27.   
  28.     devno = MKDEV(major,minor);  
  29.     ret = register_chrdev(major,"hello",&hello_ops);  
  30.   
  31.     cls = class_create(THIS_MODULE, "myclass");  
  32.     if(IS_ERR(cls))  
  33.     {  
  34.         unregister_chrdev(major,"hello");  
  35.         return -EBUSY;  
  36.     }  
  37.     test_device = device_create(cls,NULL,devno,NULL,"hello");//mknod /dev/hello  
  38.     if(IS_ERR(test_device))  
  39.     {  
  40.         class_destroy(cls);  
  41.         unregister_chrdev(major,"hello");  
  42.         return -EBUSY;  
  43.     }     
  44.     return 0;  
  45. }  
  46. static void hello_exit(void)  
  47. {  
  48.     device_destroy(cls,devno);  
  49.     class_destroy(cls);   
  50.     unregister_chrdev(major,"hello");  
  51.     printk("hello_exit \n");  
  52. }  
  53. MODULE_LICENSE("GPL");  
  54. module_init(hello_init);  
  55. module_exit(hello_exit);  

test.c

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <sys/types.h>  
  2. #include <sys/stat.h>  
  3. #include <fcntl.h>  
  4. #include <stdio.h>  
  5.   
  6.   
  7. main()  
  8. {  
  9.     int fd;  
  10.   
  11.   
  12.     fd = open("/dev/hello",O_RDWR);  
  13.     if(fd<0)  
  14.     {  
  15.         perror("open fail \n");  
  16.         return ;  
  17.     }  
  18.   
  19.   
  20.     close(fd);  
  21. }  

makefile

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. ifneq  ($(KERNELRELEASE),)  
  2. obj-m:=hello.o  
  3. $(info "2nd")  
  4. else  
  5. KDIR := /lib/modules/$(shell uname -r)/build  
  6. PWD:=$(shell pwd)  
  7. all:  
  8.     $(info "1st")  
  9.     make -C $(KDIR) M=$(PWD) modules  
  10. clean:  
  11.     rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order  
  12. endif  

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




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值