驱动学习(五)自动创建设备文件
文章目录
1. 创建设备文件的方式
1.1 手动创建
sudo mknod /dev/testchrdev0 c 200 0 上一节手动创建了字符设备文件
1.2 自动创建
linux内核为我们提供了一组函数,可以用来在模块加载时自动在/dev目录下创建设备对应的设备文件,并在模块卸载时删除该设备文件。
1.2.1 class_create
class_create(owner, name)
作用:创建一个设备文件类
owner:THIS_MODULE表示模块本身
name:设备模块名
返回值:struct class *指针(指向设备文件类)
1.2.2 device_create
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)
作用:创建一个设备文件
class:设备文件类指针(是class_create的返回值)
parent:父设备,一般为NULL
devt:设备号(主设备+次设备号)
drvdata:指向私有数据的指针,若没有私有数据,给NULL
fmt:设备文件名
...:可变参数,可有可无
返回值:成功,struct device类型的指针;失败,需要用ERR_PTR函数做判断
1.2.3 device_destroy
void device_destroy(struct class *class, dev_t devt)
作用:销毁设备文件
class:设备文件类指针
devt:设备号
1.2.4 class_destroy
void class_destroy(struct class *cls)
cls:设备文件类指针
作用:销毁设备文件类
2. 测试
测试环境:ubuntu 20.04
思路:在上一节代码的基础上添加:自动创建设备文件类(安装时)、自动创建设备文件(安装时)、自动删除代码(卸载时)。查看内核打印信息是否正确和查看字符设备文件是否创建成功来验证结果
###驱动代码
1 #include <linux/module.h> //模块驱动的头文件
2 #include <linux/cdev.h> //设备信息描述的头文件
3 #include <linux/fs.h> //静态申请设备号头文件
4 #include <linux/kdev_t.h> //设备号用到的头文件和宏函数
5 #include <linux/uaccess.h>
6 #include <linux/device.h>
7
8 #define BUF_SIZE 100
9
10 int major = 0; //主设备号
11 int min = 0; //次设备号
12 int deviceNum = 0; //完整设备号
13 struct cdev* pCdev = NULL; //描述设备信息的结构体
14 char *deviceName = "autoCreateNode";//设备名
15 char buff[BUF_SIZE] = "chrdev-test-2022-7-11";
16 struct class *pClass = NULL; //设备文件类指针
17 int devNum = 2; //设备文件数量
18
19 int testOpen(struct inode *pNode,struct file *pFile)
20 {
21 printk("------into test open------\n");
22 printk("------leave test open------\n");
23 return 0;
24 }
25 int testClose(struct inode *pNode,struct file *pFile)
26 {
27 printk("------into test close------\n");
28 printk("------leave test close------\n");
29 return 0;
30 }
31 ssize_t testRead(struct file *pFile,char __user *buf,size_t count,loff_t *pOffset)
32 {
33 int res = -1;
34 printk("------into testRead------\n");
35 if(count > BUF_SIZE-1)
36 {
37 count = BUF_SIZE - 1;
38 }
39 res = copy_to_user(buf,buff,count);
40 if(res)
41 {
42 printk("copy_to_user error\n");
43 return -EFAULT;
44 }
45 printk("copy_to_user ok\n");
46 printk("\t buff = %s\t\n",buff);
47 printk("------leave testRead------\n");
48 return count;
49 }
50
51 ssize_t testWrite(struct file *pFile,const char __user *buf,size_t count,loff_t *pOffset)
52 {
53 int res = -1;
54 printk("------into testWrite------\n");
55 if(count > BUF_SIZE-1)
56 {
57 count = BUF_SIZE - 1;
58 }
59 res = copy_from_user(buff,buf,count);
60 if(res)
61 {
62 printk("copy_from_user error\n");
63 return -EFAULT;
64 }
65 printk("copy_from_user ok\n");
66 printk("\t buff = %s\t\n",buff);
67 printk("------leave testWrite------\n");
68 return count;
69 }
70
71 struct file_operations fp_arr =
72 {
73 .owner = THIS_MODULE,
74 .open = testOpen,
75 .read = testRead,
76 .write = testWrite,
77 .release = testClose
78 };
79
80 int driverr_init(void) //模块初始化函数
81 {
82 int res = 0;
83 int i = 0;
84 struct device *pDevTmp = NULL;
85 printk("*********into driver init\n");
86 //动态申请设备号
87 res = alloc_chrdev_region(&deviceNum,min,devNum,deviceName);
88 if(res)
89 {
90 printk("alloc_chrdev_region error\n");
91 return res;
92 }
93 printk("alloc_chrdev_region OK!\n");
94 printk("major = %d minor = %d \n",MAJOR(deviceNum),MINOR(deviceNum));
95 major = MAJOR(deviceNum);
96 //创建设备
97 pCdev = cdev_alloc();
98 if(NULL == pCdev)
99 {
100 printk("cdev_alloc error\n");
101 unregister_chrdev_region(deviceNum,devNum);
102 return -1;
103 }
104 printk("cdev_alloc ok\n");
105 //设备初始化
106 cdev_init(pCdev,&fp_arr);
107 printk("cdev_init ok\n");
108 //设备与设备号关联
109 res = cdev_add(pCdev,deviceNum,devNum);
110 if(res)
111 {
112 printk("cdev_add error\n");
113 cdev_del(pCdev);
114 }
115 printk("cdev_add ok\n");
116 //创建设备文件类
117 pClass = class_create(THIS_MODULE,"autoCreateNode");
118 if(NULL == pClass)
119 {
120 printk("class_create error\n");
121 cdev_del(pCdev);
122 }
123 printk("class_create ok\n");
124 //创建设备文件
125 for(;i < devNum;i++)
126 {
127 pDevTmp = device_create(pClass,NULL,MKDEV(major,i),NULL,"autoCreateNode%d",i);
128 if(IS_ERR(pDevTmp))
129 {
130 printk("device_create error\n");
131 for(i = 0;i < devNum;i++)
132 {
133 device_destroy(pClass,MKDEV(major,i));
134 }
135 class_destroy(pClass);
136 return -2;
137 }
138 }
139 printk("device_create ok\n");
140 printk("*********leave driver init\n");
141 return 0;
142 }
143
144 void driver_clear(void) //模块清除函数
145 {
146 int i = 0;
147 printk("*********into driver clear\n");
148 for(;i < devNum; i++)
149 {
150 device_destroy(pClass,MKDEV(major,i));
151 }
152 class_destroy(pClass);
153 cdev_del(pCdev);
154 unregister_chrdev_region(deviceNum,devNum);
155 printk("*********leave driver clear\n");
156 }
157
158 module_init(driverr_init); //模块加载函数
159 module_exit(driver_clear); //模块卸载函数
160
161
162 MODULE_LICENSE("GPL");
163 MODULE_AUTHOR("cfy");
164 MODULE_ALIAS("liangzai");
165 MODULE_DESCRIPTION("2022-7-11");
###测试autoCreateNode0代码
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <string.h>
7
8 #define BUF_SIZE 100
9
10 int main()
11 {
12 int fd = open("/dev/autoCreateNode0",O_RDWR);
13 if(fd < 0)
14 {
15 printf("open autoCreateNode0 err\n");
16 return -1;
17 }
18 printf("open autoCreateNode0 ok\n");
19
20 char buf[BUF_SIZE] = {0};
21 //测试读
22 read(fd,buf,BUF_SIZE-1);
23 printf("read data:%s\n",buf);
24 bzero(buf,sizeof(buf));
25
26 //测试写
27 printf(">> input:");
28 scanf("%s",buf);
29 write(fd,buf,sizeof(buf));
30 bzero(buf,sizeof(buf));
31 read(fd,buf,BUF_SIZE-1);
32 printf("write end read data:%s\n",buf);
33
34 close(fd);
35 return 0;
36
37
38 }
###测试autoCreateNode1代码
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <string.h>
7
8 #define BUF_SIZE 100
9
10 int main()
11 {
12 int fd = open("/dev/autoCreateNode1",O_RDWR);
13 if(fd < 0)
14 {
15 printf("open autoCreateNode1 err\n");
16 return -1;
17 }
18 printf("open autoCreateNode1 ok\n");
19
20 char buf[BUF_SIZE] = {0};
21 //测试读
22 read(fd,buf,BUF_SIZE-1);
23 printf("read data:%s\n",buf);
24 bzero(buf,sizeof(buf));
25
26 //测试写
27 printf(">> input:");
28 scanf("%s",buf);
29 write(fd,buf,sizeof(buf));
30 bzero(buf,sizeof(buf));
31 read(fd,buf,BUF_SIZE-1);
32 printf("write end read data:%s\n",buf);
33
34 close(fd);
35 return 0;
36
37
38 }
查看内核打印信息
创建设备文件类成功、创建设备文件成功,查看设备文件
设备文件创建成功,测试能否正常打开关闭
autoCreateNode0读写无误
完整内核打印信息,打开、读写、关闭,都没有问题
autoCreateNode1读写无误
所有打印信息,autoCreateNode0读写读、autoCreateNode1读写读