一、Linux内核对设备的分类
在Linux系统中,文件类型多种多样,不同类型的文件通过特定标识进行区分:
- -:普通文件
- d:目录文件
- p:命名管道文件
- s:本地socket通信文件
- l:符号链接文件
- c:字符设备文件
- b:块设备文件
根据驱动程序的设计模型与实现方式,Linux内核将硬件设备划分为以下三大类:
字符设备
以字节流方式进行数据读写操作的设备。通常按顺序访问,适用于传输数据量较小的场景,一般不设置缓存机制。
块设备
以固定大小的数据块为单位进行读写的设备。最小单位为512字节(即一个扇区),且块大小必须是扇区的整数倍。Linux系统中常见的块大小为4096字节。支持随机访问,并通过缓存机制提升读写效率。
网络设备
用于处理网络数据包的接收与发送,是网络通信的关键组成部分。
二、设备号——内核中区分同类设备的标识
为了在内核中准确识别同一类别下的不同设备,Linux使用“设备号”作为唯一标识。设备号为一个32位无符号整数,类型定义为dev_t,其结构由两部分组成:
- 主设备号(高12位):表示管理该类设备的驱动程序
- 次设备号(低20位):标识具体被操作的设备实例
当应用程序打开某个设备文件时,内核会依据该文件关联的设备号查找对应的设备管理结构,从而完成设备定位。
常用宏定义用于设备号的操作:
MKDEV:将主设备号和次设备号合并成完整的32位设备号。
dev_t devno;
int major = 251;//主设备号
int minor = 2;//次设备号
devno = MKDEV(major,minor);
MAJOR:从完整的设备号中提取主设备号。
dev_t devno = MKDEV(249,1);
int major = MAJOR(devno);
MINOR:从完整的设备号中提取次设备号。
dev_t devno = MKDEV(249,1);
int minor = MINOR(devno);
若已知某设备的主设备号与次设备号,用户可在应用层通过mknod命令在/dev目录下创建相应的设备节点文件。创建完成后,对该文件的所有操作将直接映射到对应硬件设备上。
命令格式如下:
@ cd /dev
@ mknod 设备文件名 设备种类(c为字符设备,b为块设备) 主设备号 次设备号 //ubuntu下需加sudo执行
此外,在程序中也可通过系统调用mknod()动态创建设备节点,其函数原型为:
int mknod(const char *pathname,mode_t mode,dev_t dev);
pathname:带路径的设备文件名,无路径默认为当前目录,一般都创建在/dev下
mode:文件权限 位或 S_IFCHR/S_IFBLK
dev:32位设备号
返回值:成功为0,失败-1
三、设备号的申请与释放
字符设备驱动开发的第一步是在模块入口函数中注册驱动框架,主要包括两个核心步骤:
- 向内核申请设备号
- 定义并初始化代表该设备的结构体,将其注册到内核中
int register_chrdev_region(dev_t from, unsigned count, const char *name)
功能:手动分配设备号,先验证设备号是否被占用,如果没有则申请占用该设备号
参数:
from:自己指定的设备号
count:申请的设备数量
name:/proc/devices文件中与该设备对应的名字,方便用户层查询主设备号
返回值:
成功为0,失败负数,绝对值为错误码
int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count, const char *name)
功能:动态分配设备号,查询内核里未被占用的设备号,如果找到则占用该设备号
参数:
dev:分配设备号成功后用来存放分配到的设备号
baseminior:起始的次设备号,一般为0
count:申请的设备数量
name:/proc/devices文件中与该设备对应的名字,方便用户层查询主次设备号
返回值:
成功为0,失败负数,绝对值为错误码
成功申请后,可在/proc/devices文件中查看当前已注册的主设备号及其对应的设备名称。此信息可用于后续使用mknod命令创建设备节点时的参数参考。
void unregister_chrdev_region(dev_t from, unsigned count)
功能:释放设备号
参数:
from:已成功分配的设备号将被释放
count:申请成功的设备数量
当设备模块卸载时,应主动释放所占用的设备号资源,此时/proc/devices中对应的记录也将被清除。


雷达卡


京公网安备 11010802022788号







