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(...) 函数

功能:创建一个类;

下面是具体定义:

 

 
  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)源代码如下:

 

 
  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)

 
  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 *

下面是源码解析:

 

 
  1. struct device *device_create(struct class *class, struct 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)解析如下:

 

 
  1. struct device *device_create_vargs(struct class *class, struct 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

 

 
  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

 

 
  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

 

 
  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几个名字的对应关系:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值