下面是自己写的一个测试程序, 加载模块后将会在/dev目录下动态创建名为”test”的字符设备文件,并在class目录下生成相关文件.
首先在虚拟机上执行:
[root@FLYING ~]# ps -aux | grep "udev"
root 452 0.0 0.2 2244 608 ? S
root 2531 0.0 0.2 3980 632 pts/0 R+ 00:53 0:00 grep udev
确定udev进程存在, udev会动态创建设备文件.
在加载模块后,我们需要看以下的内容:
[root@FLYING ~]# ls -l /dev/test
crw------- 1 root root 100, 0 2020-03-30 00:56 /dev/test //在/dev目录下动态生成test字符设备文件
[root@FLYING andy]# pwd
/sys/class/andy //在class目录下生成andy目录
[root@FLYING andy]# tree
.
|-- classfile
`-- test
|-- dev
|-- devfile
|-- power
| `-- wakeup
|-- subsystem -> ../../andy
`-- uevent
3 directories, 5 files
|
文件: |
class.rar |
大小: |
1KB |
下载: |
下载 | |
下面看看代码,我们是怎么实现的:
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12
13
14 #define MAJOR_NUM 100
15 static struct class *test_class;
16 static struct device *test_device;
17
18
19 int char_dev_open(struct inode *inode, struct file *file)
20 {
21 printk(KERN_INFO "test open char dev\n");
22 return 0;
23 }
24
25 ssize_t char_dev_read (struct file *file, char __user *buf,
26 size_t count, loff_t *ppos)
27 {
28 printk(KERN_INFO "test read char dev\n");
29 return 0;
30 }
31
32 static struct file_operations testopt = {
33 .owner = THIS_MODULE,
34 .open = char_dev_open,
35 .read = char_dev_read,
36 };
37
38 static ssize_t classfile_sysfs_show(struct class *class, char *buf)
39 {
40 printk(KERN_INFO "class file show \n");
41 return 0;
42 }
43
44 static ssize_t devfile_sysfs_show(struct device *dev, struct device_attribute *attr,
45 char *buf)
46 {
47 printk(KERN_INFO "dev file show \n");
48 return 0;
49 }
50
51 static CLASS_ATTR(classfile, S_IRUGO, classfile_sysfs_show, NULL);
52 static DEVICE_ATTR(devfile, S_IRUGO, devfile_sysfs_show,NULL);
53
54 static int __init class_test_init(void)
55 {
56 int err;
57
58 err = register_chrdev(MAJOR_NUM ,"test" ,&testopt);
59 if(err)
60 goto error;
61
62 test_class = class_create(THIS_MODULE, "andy");
63 if(IS_ERR(test_class)){
64 err = PTR_ERR(test_class);
65 goto class_error;
66 }
67
68 test_device = device_create(test_class, NULL ,MKDEV(MAJOR_NUM ,0) ,"test");
69 if(IS_ERR(test_device)){
70 err = PTR_ERR(test_device);
71 goto device_error;
72 }
73
74 err = class_create_file(test_class , &class_attr_classfile);
75 if(err)
76 goto error;
77 err = device_create_file(test_device ,&dev_attr_devfile);
78 if(err)
79 goto error;
80 return 0;
81
82 device_error:
83 class_destroy(test_class);
84 class_error:
85 unregister_chrdev(MAJOR_NUM ,"test");
86 error:
87 return err;
88 }
89
90 void __exit class_test_exit(void)
91 {
92 unregister_chrdev(MAJOR_NUM ,"test");
93 class_remove_file(test_class, &class_attr_classfile);
94 device_remove_file(test_device,&dev_attr_devfile);
95 device_destroy(test_class,MKDEV(MAJOR_NUM ,0));
96 class_destroy(test_class);
97 return;
98 }
99
100
101 module_init(class_test_init);
102 module_exit(class_test_exit);
103 MODULE_LICENSE("GPL");
104 MODULE_DESCRIPTION("andy wang for sys class device test");
#
# Makefile for the class device test.
#
obj-m += class_test.o
KERNAL_PATH = /usr/src/linux-2.6.26
default:
make -C $(KERNAL_PATH) M=$(PWD) modules
clean:
rm *.o *.ko *.mod.c *.order *.symvers
第58行, 注册一个字符设备”test”
第62,创建一个名字为andy的类class ,此时在/sys/class目录下就生成了andy目录.
第68行, 创建一个名字为“test”的类文件 ,此时就会在andy目录下生成test目录了.
第74行,创建一个类属性文件, 也就是在andy目录下创建一个名为”classfile”的类属性文件.
第77行, 创建一个设备属性文件 ,也就是在test目录下建立一个名为”devfile”的设备属性文件.
那么/dev/test设备文件是如何动态生成的呢?
先看看流程:
device_create()->device_register()->device_add()->kobject_uevent()
最关键的函数就是kobject_uevent()了 , 这个函数将action_string=add,devpath=/class/andy
,subsystem=class等环境变量信息发给用户层的udev, 然后udev会找到devpath目录下的dev文件(存放着设备号)然后在/dev目录下动态创建设备文件,所以我们上面要看看udev进程是否存在了。