
一、文件操作集简介
在 Linux 设备驱动开发中,注册字符设备时,我们需要将 cdev 结构体(设备描述信息)和 file_operations 结构体(驱动功能入口)关联起来。具体步骤是:
- 通过
cdev_init()函数把设备信息(cdev)和功能操作表(file_operations)绑定在一起 file_operations结构就像一个功能目录,里面存放着驱动程序的各种操作函数地址- 当用户程序通过系统调用访问设备时,内核会自动到这个目录里找到对应的函数地址
- 然后直接执行驱动程序里预先写好的对应功能代码
简单理解
file_operations 就是驱动程序和系统调用之间的连接桥梁,它把程序请求和驱动功能对应起来,让设备操作能够顺利执行。
file_operations 结构体定义在 内核源码/include/linux/fs.h 文件中。下面对部分常用函数进行说明:

owner 是第一个 file_operations 成员,它并不是一个操作,而是一个指向拥有该结构的模块的指针,避免正在操作时被卸载,一般为初始化为 THIS_MODULE。

read 函数指针用来从设备中同步读取数据,读取成功返回读取的字节数。与应用程序中的 read 函数对应。

write 函数指针用来发送数据给设备,写入成功返回写入的字节数。与应用程序中的 write 函数对应。

unlocked_ioctl 函数指针提供对于设备的控制功能,与应用程序中的 ioctl 函数对应。

open 函数指针用于打开设备,与应用程序中的 open 函数对应。

release 函数指针在 file 结构体释放时被调用。
至此对于 file_operations 文件操作集的部分常用函数就介绍完了,填充了部分常用函数的 file_operations 结构体如下:

二、实验代码
源代码下载
bash
git clone git@gitee.com:yangxuesong314/linux-driver.git1
- 代码位于:
linux-driver/05.字符设备驱动模型/04.文件操作集
c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
static int chrdev_open(struct inode *inode, struct file *file)
{
printk("This is chrdev_open \n");
return 0;
}
static ssize_t chrdev_read(struct file *file, char __user *buf, size_t size, loff_t *off)
{
printk("This is chrdev_read \n");
return 0;
}
static ssize_t chrdev_write(struct file *file, const char __user *buf, size_t size, loff_t *off)
{
printk("This is chrdev_write \n");
return 0;
}
static int chrdev_release(struct inode *inode, struct file *file)
{
return 0;
}
static dev_t dev_num;
static struct cdev cdev_test;
static struct file_operations cdev_fops_test = {
.owner = THIS_MODULE,
.open = chrdev_open,
.read = chrdev_read,
.write = chrdev_write,
.release = chrdev_release,
};
static struct class *class_test;
static int __init chrdev_fops_init(void)
{
int ret;
int major, minor;
ret = alloc_chrdev_region(&dev_num, 0, 1, "chrdev_name");
if (ret < 0) {
printk("alloc_chrdev_region is error \n");
}
printk("alloc_chrdev_region is ok \n");
major = MAJOR(dev_num);
minor = MINOR(dev_num);
printk("major is %d\n",major);
printk("minor is %d\n",minor);
cdev_init(&cdev_test, &cdev_fops_test);
cdev_test.owner = THIS_MODULE;
ret = cdev_add(&cdev_test, dev_num, 1);
if (ret < 0) {
printk("cdev_add is error \n");
}
printk("cdev_add is ok \n");
class_test = class_create(THIS_MODULE, "class_test");
device_create(class_test, NULL, dev_num, NULL, "device_test");
return 0;
}
static void __exit chrdev_fops_exit(void)
{
device_destroy(class_test, dev_num);
class_destroy(class_test);
cdev_del(&cdev_test);
unregister_chrdev_region(dev_num, 1);
printk("module exit \n");
}
module_init(chrdev_fops_init);
module_exit(chrdev_fops_exit);
MODULE_LICENSE("GPL v2");1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
应用代码:
c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd;
char buf[32];
fd = open(argv[1], O_RDWR, 0666);
if (fd < 0) {
printf("open is error\n");
return -1;
}
printf("open is ok\n");
if (!strcmp(argv[2], "read")) {
read(fd, buf, 32);
} else if (!strcmp(argv[2], "write")) {
write(fd,"hello\n",6);
}
close(fd);
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
三、实验运行结果
