08、文件私有数据实验
在驱动开发中,通常会为每个设备创建一个设备结构体,用来存放该设备的硬件信息。本章将讲解设备结构体的工作原理以及如何处理文件中的私有数据。
一、文件私有数据简介
在Linux系统中,虽然没有强制要求使用文件私有数据,但驱动开发中广泛采用这一方法,这已成为一种常见做法,同时也体现了面向对象的设计理念。Linux的struct file
结构体中专门设置了一个字段(域),供驱动程序存储自己的私有数据。这一结构体定义在linux/fs.h
头文件中。
在Linux设备驱动中,文件私有数据(private_data)是一个常用方法。它的作用是将设备结构体的地址保存到文件私有数据指针中,这样就能在打开设备(open函数)时记录设备信息,并在后续的读(read)、写(write)操作中直接使用这些数据。具体来说:
- open函数中:将设备结构体的地址赋值给private_data;
- read/write函数中:通过private_data获取设备信息,执行具体操作。
这种方式让设备信息在驱动的不同函数之间传递变得简单直接。
C
struct device test dev1;
static int cdev_test_open(struct inode *inode,struct file *file){
file->private_data=&dev1;
return O;
};
1
2
3
4
5
2
3
4
5
在代码中,我们首先创建了一个名为dev1的设备信息结构。当设备被打开时(在open函数里),我们把设备的私有数据指针(private_data)设置为指向这个dev1结构。这样在后续的读操作(read函数)和写操作(write函数)中,就可以直接通过这个私有数据指针访问到设备的dev1结构里的数据了。
C
static ssize _t cdev test_write(struct file *file,const char user *buf, size_t size,loff t *off t){
struct device_test *test_dev=(struct device_test *)file->private_data;
return O;
1
2
3
2
3
二、实验程序编写
C
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
struct device_test{
dev_t dev_num; //设备号
int major ; //主设备号
int minor ; //次设备号
struct cdev cdev_test; // cdev
struct class *class; //类
struct device *device; //设备
char kbuf[32]; //缓存区buf
};
struct device_test dev1; //定义一个device_test结构体变量
/*打开设备函数*/
static int cdev_test_open(struct inode *inode, struct file *file)
{
file->private_data=&dev1; //设置私有数据
printk("This is cdev_test_open\r\n");
return 0;
}
/*向设备写入数据函数*/
static ssize_t cdev_test_write(struct file *file, const char __user *buf, size_t size, loff_t *off)
{
struct device_test *test_dev=(struct device_test *)file->private_data; //在write函数中读取private_data
if (copy_from_user(test_dev->kbuf, buf, size) != 0) // copy_from_user:用户空间向内核空间传数据
{
printk("copy_from_user error\r\n");
return -1;
}
printk("This is cdev_test_write\r\n");
printk("kbuf is %s\r\n", test_dev->kbuf); //打印kbuf的值
return 0;
}
/**从设备读取数据*/
static ssize_t cdev_test_read(struct file *file, char __user *buf, size_t size, loff_t *off)
{
struct device_test *test_dev=(struct device_test *)file->private_data;
if (copy_to_user(buf, test_dev->kbuf, strlen( test_dev->kbuf)) != 0) // copy_to_user:内核空间向用户空间传数据
{
printk("copy_to_user error\r\n");
return -1;
}
printk("This is cdev_test_read\r\n");
return 0;
}
static int cdev_test_release(struct inode *inode, struct file *file)
{
printk("This is cdev_test_release\r\n");
return 0;
}
/*设备操作函数*/
struct file_operations cdev_test_fops = {
.owner = THIS_MODULE, //将owner字段指向本模块,可以避免在模块的操作正在被使用时卸载该模块
.open = cdev_test_open, //将open字段指向chrdev_open(...)函数
.read = cdev_test_read, //将open字段指向chrdev_read(...)函数
.write = cdev_test_write, //将open字段指向chrdev_write(...)函数
.release = cdev_test_release,//将open字段指向chrdev_release(...)函数
};
static int __init chr_fops_init(void) //驱动入口函数
{
/*注册字符设备驱动*/
int ret;
/*1 创建设备号*/
ret = alloc_chrdev_region(&dev1.dev_num, 0, 1, "alloc_name"); //动态分配设备号
if (ret < 0)
{
printk("alloc_chrdev_region is error\n");
}
printk("alloc_chrdev_region is ok\n");
dev1.major = MAJOR(dev1.dev_num); //获取主设备号
dev1.minor = MINOR(dev1.dev_num); //获取次设备号
printk("major is %d \r\n", dev1.major); //打印主设备号
printk("minor is %d \r\n", dev1.minor); //打印次设备号
/*2 初始化cdev*/
dev1.cdev_test.owner = THIS_MODULE;
cdev_init(&dev1.cdev_test, &cdev_test_fops);
/*3 添加一个cdev,完成字符设备注册到内核*/
cdev_add(&dev1.cdev_test, dev1.dev_num, 1);
/*4 创建类*/
dev1. class = class_create(THIS_MODULE, "test");
/*创建设备*/
dev1.device = device_create(dev1.class, NULL, dev1.dev_num, NULL, "test");
return 0;
}
static void __exit chr_fops_exit(void) //驱动出口函数
{
/*注销字符设备*/
unregister_chrdev_region(dev1.dev_num, 1); //注销设备号
cdev_del(&dev1.cdev_test); //删除cdev
device_destroy(dev1.class, dev1.dev_num); //删除设备
class_destroy(dev1.class); //删除类
}
module_init(chr_fops_init);
module_exit(chr_fops_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("topeet");
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122