type
date
slug
category
icon
password
在
linux
中,我们使用设备编号来表示设备,主设备号区分设备类别,次设备号标识具体的设备。cdev
结构体被内核用来记录设备号,使用设备时,通常会打开设备节点,通过设备节点inode
结构体、file
结构体最终找到 file_operation
结构体,并从 file_operation
结构体获得操作设备的具体方法。设备号
每一行表示一个设备,每一行的第一个字符表示设备的类型。
c
用来标识字符设备
b
用来标识块设备
如
autofs
是一个字符设备c
, 它的主设备号是10(指向设备驱动程序),次设备号是235(指向某个具体设备)。内核中设备编号的含义
内核中,设备编号用
dev_t
表示,dev_t
是一个32位的数,其中,高12位表示主设备号,低20位表示次设备号。 通过移位操作,从设备编号中得到主、次设备号。同样可以通过主次设备号位运算变成dev_t 类型的设备编号。
cdev结构体
内核通过一个散列表(哈希表)来记录设备编号。 哈希表由数组和链表组成,吸收数组查找快,链表增删效率高,容易拓展等优点。
以主设备号为
cdev_map
编号,使用哈希函数f(major)=major%255
来计算组数下标(使用哈希函数是为了链表节点尽量平均分布在各个数组元素中,提高查询效率); 主设备号冲突,则以次设备号为比较值来排序链表节点。
- struct kobject kobj:内嵌内核对象,将设备同意加入到“linux设备驱动模型‘’中管理(如对象的引用技术、电源管理、热插拔、生命周期、与用户通信等)
- struct module *owner:字符设备驱动程序所在的内核模块对象的指针。
- const struct file_operations *ops:文件操作,是字符设备驱动中非常重要的数据结构。应用程序通过文件系统(VFS)呼叫设备驱动程序中实现的文件操作类函数过程中,ops起着桥梁纽带作用。VFS与设备文件之间的接口是file_operations结构体成员函数,这个结构体包含了对文件进行打开、关闭、读写、控制等一系列成员函数。
- struct list_head list:用于将系统中的字符设备形成链表(这是个内核链表的一个链接,可以再内核很多结构体中看到这种结构的身影)
- dev_t dev:字符设备的设备号,有主设备和次设备号构成。
- unsigned int count: 属于同一主设备号下次设备号的个数,用于表示驱动控制的同类设备的实际数量。
设备节点
设备节点(设备文件):Linux中通过
mknod
命令来创建设备节点,设备节点是Linux内核对设备的抽象。设备节点创建在
/dev
下,是连接内核与用户层的枢纽,设备是接到哪种接口的哪个ID 上。数据结构
序号 | 结构体 | 描述 | 备注 |
1 | file_operations | 文件操作 | 关联系统调用和驱动程序 |
2 | file | 文件描述 | 已经打开的文件描述符 |
3 | inode | 索引节点 | 存储文件元数据 |
file_operations 结构体

file_operations结构体向系统提供设备驱动程序接口,结构体中每个成员对应一个系统调用。以下代码中只列出本章使用到的部分函数。
- llseek: 修改文件的当前读写位置,并返回偏移后的位置。
- 参数file:对应文件指针;
- 参数loff_t:指定偏移量的大小;
- 参数int:进行偏移位置,SEEK_SET,SEEK_CUR,SEEK_END。
- read:读取设备中数据
- 参数file:对应文件指针;
- 参数char __user*: 数据缓冲区,地址空间是用户空间的,内核模块不能直接使用,需要使用copy_to_user函数操作;
- 参数loff_t:指定偏移量的大小。
- write:向设备写入数据
- 参数file:对应文件指针;
- 参数char __user*: 数据缓冲区,地址空间是用户空间的,内核模块不能直接使用,需要使用copy_from_user函数操作;
- 参数loff_t:指定偏移量的大小。
- unlocked_ioctl: 提供设备执行相关控制命令的实现方法,它对应于应用程序的
fcntl
函数以及ioctl
函数。在 kernel 3.0 中已经完全删除了 struct file_operations 中的 ioctl 函数指针。
- open: 设备驱动第一个被执行的函数,一般用于硬件的初始化。
- release: 当file结构体被释放时,将会调用该函数。与open函数相反,该函数可以用于释放
我们提到read和write函数时,需要使用copy_to_user函数以及copy_from_user函数来进行数据访问,写入/读取成 功函数返回0,失败则会返回未被拷贝的字节数。
file结构体
每打开一个文件,内核会创建一个结构体,内核中用
file
结构体来表示每个打开的文件。文件的操作函数是该结构体的成员变量
f_op
f_op
:存放与文件操作相关的一系列函数指针,如open、read、wirte等函数。
private_data
:该指针变量只会用于设备驱动程序中,内核并不会对该成员进行操作。因此,在驱动程序中,通常用于指向描述设备的结构体。
inode结构体
包含文件访问权限、属主、组、大小、生成时间、访问时间、最后修改时间等信息。
一个文件描述符(file文件结构)表示一个已经打开的设备,多个文件描述符可以表示同个文件多个打开实例。但此时这些file文件全部只能指向同一个
inode
结构体。dev_t i_rdev
: 表示设备文件的结点,这个域实际上包含了设备号。
struct cdev *i_cdev
:struct cdev
是内核的一个内部结构,它是用来表示字符设备的,当inode
结点指向一个字符设备文件时,此域为一个指向inode结构的指针。
- Author:felixfixit
- URL:http://www.felixmicrospace.top/article/linux_drv_chrdev
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!