This chapter introduced the following symbols and header files. The list of the fields in struct file_operations and struct file is not repeated here.
本章介绍了设备驱动开发的核心头文件、数据类型、函数及宏,以下是关键内容的整理。该文内容在阅读本章的任何时刻都可以过来查阅。
1. 核心头文件
| 头文件路径 | 核心作用 |
|---|
<linux/types.h> | 定义设备号基础类型 dev_t,以及 MAJOR()/MINOR()/MKDEV() 设备号操作宏。 |
<linux/fs.h> | 驱动开发核心头文件,声明设备号分配 / 释放函数(如 register_chrdev_region)、struct file_operations/struct file/struct inode 结构,以及文件操作相关接口。 |
<linux/cdev.h> | 管理字符设备核心结构 struct cdev,提供 cdev_alloc()/cdev_init()/cdev_add()/cdev_del() 等函数。 |
<linux/kernel.h> | 提供内核基础工具,如 container_of 宏(通过结构体成员指针获取结构体指针)、printk 日志函数。 |
<asm/uaccess.h> | 声明用户空间与内核空间数据传输函数,如 copy_from_user()/copy_to_user(),确保数据安全访问。 |
<linux/module.h> | 模块开发基础头文件,定义 THIS_MODULE 宏(用于 file_operations/struct cdev 的 owner 字段)、module_init()/module_exit() 等模块入口宏。 |
2. 关键数据类型
| 数据类型 | 核心作用 |
|---|
dev_t | 32 位设备号类型,包含 12 位主设备号和 20 位次设备号,用于唯一标识字符 / 块设备。 |
struct cdev | 内核表示字符设备的核心结构,关联设备操作集(file_operations)与设备号,需通过 cdev_add() 注册到内核。 |
struct inode | 内核表示文件元信息的结构,设备文件的 inode 中,i_rdev 存储设备号,i_cdev 指向对应的 struct cdev。 |
3. 核心函数与宏
| 函数 / 宏 | 所属头文件 | 核心作用 |
|---|
MAJOR(dev_t dev) | <linux/types.h> | 从 dev_t 中提取主设备号。 |
MINOR(dev_t dev) | <linux/types.h> | 从 dev_t 中提取次设备号。 |
MKDEV(major, minor) | <linux/types.h> | 由主、次设备号组合生成 dev_t 类型设备号。 |
register_chrdev_region(dev_t first, unsigned int count, char *name) | <linux/fs.h> | 静态分配设备号范围,适用于已知主设备号的场景。返回 0 成功,负数失败。 |
alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name) | <linux/fs.h> | 动态分配设备号范围,dev 输出分配的起始设备号。返回 0 成功,负数失败。 |
unregister_chrdev_region(dev_t first, unsigned int count) | <linux/fs.h> | 释放通过上述两个函数分配的设备号范围,需在模块清理时调用。 |
cdev_alloc(void) | <linux/cdev.h> | 动态分配独立的 struct cdev 结构,... |
4. 汇总表
| 头文件 | 函数 / 类型 / 宏 | 描述 |
|---|
linux/types.h | dev_t | 内核中用于表示设备号的数据类型 |
int MAJOR(dev_t dev) | 从设备号中提取主设备号的宏 |
int MINOR(dev_t dev) | 从设备号中提取次设备号的宏 |
dev_t MKDEV(unsigned int major, unsigned int minor) | 从主设备号和次设备号构建 dev_t 的宏 |
| | |
| linux/fs.h | 编写设备驱动所需的 "文件系统" 头文件,声明了许多重要的函数和数据结构 |
int register_chrdev_region(dev_t first, unsigned int count, char *name) | 用于分配字符设备号范围的函数,适用于已知所需主设备号的情况 |
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name) | 动态分配字符设备号范围的函数 |
void unregister_chrdev_region(dev_t first, unsigned int count) | 释放设备号范围的函数 |
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops) | 旧版 (2.6 之前) 的字符设备注册函数,2.6 内核中仍有模拟但不推荐新代码使用。若主设备号不为 0 则直接使用,否则动态分配 |
int unregister_chrdev(unsigned int major, const char *name) | 撤销由 register_chrdev 注册的设备。major 和 name 必须与注册时使用的值相同 |
struct file_operations | 大多数设备驱动使用的重要数据结构,包含字符驱动的方法 |
struct file | 表示一个打开的文件的结构 |
struct inode | 表示磁盘上一个文件的结构 |
| | |
| linux/cdev.h | 包含用于管理 cdev 结构的函数,cdev 结构在内核中表示字符设备 |
struct cdev *cdev_alloc(void) | 分配 cdev 结构的函数 |
void cdev_init(struct cdev *dev, struct file_operations *fops) | 初始化 cdev 结构的函数 |
int cdev_add(struct cdev *dev, dev_t num, unsigned int count) | 向内核添加 cdev 结构的函数 |
void cdev_del(struct cdev *dev) | 从内核删除 cdev 结构的函数 |
| linux/kernel.h | container_of(pointer, type, field) | 一个便捷宏,用于从包含在某个结构中的字段的指针获取该结构的指针 |
| | |
| asm/uaccess.h | 声明内核代码用于在用户空间和内核空间之间移动数据的函数 |
unsigned long copy_from_user(void *to, const void *from, unsigned long count) | 在用户空间和内核空间之间复制数据 (从用户空间到内核空间) |
unsigned long copy_to_user(void *to, const void *from, unsigned long count) | 在用户空间和内核空间之间复制数据 (从内核空间到用户空间) |
技术交流,欢迎加入社区:GPUers。