1. 程式人生 > >Linux 字元裝置驅動結構(二)—— 自動建立裝置節點

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. cls = kzalloc( sizeof(*cls), GFP_KERNEL);
  7. if (!cls) {
  8. retval = -ENOMEM;
  9. goto error;
  10. }
  11. cls->name = name;
  12. cls->owner = owner;
  13. cls->class_release = class_create_release;
  14. retval = __class_register(cls, key);
  15. if (retval)
  16. goto error;
  17. return cls;
  18. error:
  19. kfree(cls);
  20. return ERR_PTR(retval);
  21. }
  22. 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. class_unregister(cls);
  6. }


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. va_start(vargs, fmt);
  7. dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
  8. va_end(vargs);
  9. return dev;
  10. }

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. static int major = 250;
  6. static int minor= 0;
  7. static dev_t devno;
  8. static struct class *cls;
  9. static struct device *test_device;
  10. static int hello_open (struct inode *inode, struct file *filep)
  11. {
  12. printk( "hello_open \n");
  13. return 0;
  14. }
  15. static struct file_operations hello_ops=
  16. {
  17. .open = hello_open,
  18. };
  19. static int hello_init(void)
  20. {
  21. int ret;
  22. printk( "hello_init \n");
  23. devno = MKDEV(major,minor);
  24. ret = register_chrdev(major, "hello",&hello_ops);
  25. cls = class_create(THIS_MODULE, "myclass");
  26. if(IS_ERR(cls))
  27. {
  28. unregister_chrdev(major, "hello");
  29. return -EBUSY;
  30. }
  31. test_device = device_create(cls, NULL,devno, NULL, "hello"); //mknod /dev/hello
  32. if(IS_ERR(test_device))
  33. {
  34. class_destroy(cls);
  35. unregister_chrdev(major, "hello");
  36. return -EBUSY;
  37. }
  38. return 0;
  39. }
  40. static void hello_exit(void)
  41. {
  42. device_destroy(cls,devno);
  43. class_destroy(cls);
  44. unregister_chrdev(major, "hello");
  45. printk( "hello_exit \n");
  46. }
  47. MODULE_LICENSE( "GPL");
  48. module_init(hello_init);
  49. 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. main()
  6. {
  7. int fd;
  8. fd = open( "/dev/hello",O_RDWR);
  9. if(fd< 0)
  10. {
  11. perror( "open fail \n");
  12. return ;
  13. }
  14. close(fd);
  15. }

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幾個名字的對應關係: