字符设备框架

通用头文件

以下三个头文件几乎所有的linux驱动代码都需要

1
2
3
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>

设备结构体并创建设备对象

定义设备结构体

1
2
3
4
5
6
7
8
9
10
11
12

#define xxx_CNT 1 //设备数量
#define xxx_NAME "xxx" //驱动名称

struct xxx_dev{
dev_t devid; //设备号
int major; //主设备号
int minor; //从设备号
struct cdev cdev; //cdev结构体
struct class *class; //类结构体
struct device *dev; //设备结构体
}

cdev 需要包含头文件#include <linux/cdev.h>
class和device需要包含头文件#include <linux/devices.h>

创建设备对象

1
struct xxx_dev xxx;

file_operation集各项函数具体实现

open函数具体实现

1
2
3
4
5
static int xxx_open(struct inode *inode, struct file *filp)
{
filp->private_data = &xxx; 将设备结构体对象设为私有数据
return 0;
}

read函数具体实现

1
2
3
4
5
6
7
static ssize_t xxx_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
struct xxx_dev *dev = (xxx_dev *)filp->private_data; //获取私有数据
copy_to_user(目标buf, 源, cnt);
...
return 0;
}

copy_to_uaer函数需要包含头文件#include <asm/uaccess.h>

write函数具体实现

1
2
3
4
5
6
static ssize_t xxx_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
copy_from_user(目标buf, 源, cnt);
...
return 0;
}

release函数具体实现

1
2
3
4
static int XXX_release(struct inode *inode, struct file *filp)
{
return 0;
}

设备操作函数集合 需包含头文件#include <linux/fs.h>

1
2
3
4
5
6
7
8
9
struct file_operations xxx_fops=
{
.owner = THIS_MODUle, //模块拥有者
.open = xxx_open, //open函数具体实现
.read = xxx_read, //read函数具体实现
.write = xxx_write, //write函数具体实现
.release = xxx_release, //release函数具体实现
...
};

模块入口函数

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
static int __init xxx_init(void)
{
...
...
/* 分配设备号 */
if(xxx.major) //如果已经分配主设备号
{
xxx.devid = MKDIR(xxx.major, 0); //创建设备号
register_chrdev_region(XXX.devid, xxx_CNT, xxx_NAME); //注册设备号
}
else
{
alloc_chrdev_region(&xxx.devid, 0, xxx_CNT, xxx_NAME); //分配设备号 0为从设备号起始值
xxx.major = MAJOR(xxx.devid);
xxx.minor = MINOR(xxx.devid);
}

/*初始化cdev*/
xxx.cdev.owner = THIS_MODULE;
cdev_init(&xxx.cdev, &xxx_fops);
/*添加cdev*/
cdev_add(&xxx.cdev, xxx.devid, xxx_CNT);

/* 创建类 */
xxxx->class = class_create(THIS_MODULE, xxx_NAME);
/* 类下创建设备 */
xxx->device = device_create(xxx.class, NULL, xxx.devid, NULL, xxx_NAME);

...
...
return 0;
}

出口函数形式

1
2
3
4
5
6
7
8
static void __exit xxx_exit(void)
{
cdev_del(&xxx.cdev); //删除cdev
unregister_chrdev_region(xxx.devid, xxx_CNT); //注销字符设备
device_destroy(xxx->class, xxx->device);
class_destroy(xxx->class);
...
}

模块入口和模块出口

1
2
3
4
module_init(xxx_init);    //模块入口
module_exit(xxx_exit); //模块出口
MODULE_LICENSE("GPL"); //模块协议
MODULE_AUTHOR("Hector"); //模块作者

字符设备框架
http://example.com/2022/09/22/字符设备框架/
作者
Hector
发布于
2022年9月22日
许可协议