字符设备的注册分为两部分:注册设备号、注册设备本身。下面的函数都可用于注册设备号,只是注册的方式不同。
目录
1、静态分配设备号 —— register_chrdev_region
2、动态分配设备号 —— alloc_chrdev_region
3、释放设备号 —— unregister_chrdev_region
一、认识设备号
Linux中每一个设备都有一个设备号,使用 dev_t 类型表示,本质是一个 32 位的无符号整型。每个设备号包含主设备号和次设备号两部分
- 主设备号:高 12 位。表示某一个具体的驱动
- 次设备号:低 20 位。表示某个驱动的各个设备
在内核源码的 include/linux/kdev.h 中提供了设备号的操作函数
二、早期字符设备注册 / 注销函数(不推荐)
一个设备号分为主设备号和次设备号,在早期的字符设备注册 / 注销函数中,只需要指定主设备号。函数声明如下:
// 字符设备注册
static inline int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops);
// 字符设备注销
static inline void unregister_chrdev(unsigned int major, const char *name);
register_chrdev 参数解析
major:主设备号,Linux 下每个设备都有一个设备号,可以使用cat /proc/devices 查看已经使用的设备号。静态分配时注意不要和已有设备号重复;如果要动态分配,可以参考下面《设备号的分配》
name:设备名称,当驱动注册成功以后,在 /dev/ 下显示的名称
fops:当前驱动的操作函数集合,函数声明放在file_operations结构体中,这里要传入的就是file_operations结构体指针。
unregister_chrdev 参数解析
major:要注销的设备对应的主设备号。
name:要注销的设备对应的设备名。
三、新字符设备注册 / 注销函数
1、静态分配设备号 —— register_chrdev_region
如果已经存在了主设备号(即之前已经注册过该类型的字符设备),只需要我们自己指定一个次设备号的话,我们推荐使用静态分配。
int register_chrdev_region(dev_t from, \
unsigned count, \
const char *name);
from:要申请的起始设备号(该函数支持一次注册多个设备)
count:要申请的设备号数量
name:设备名称
int major = 200;
int minor = 0;
dev_t devid = MKDEV(major, minor); // 第一个参数是主设备号,第二个参数是次设备号
register_chrdev_region(devid, 1, "test");
2、动态分配设备号 —— alloc_chrdev_region
动态分配设备号时,系统会自动给你一个没有被使用的设备号,这样就避免了冲突,卸载驱动时释放掉这个设备号即可。函数声明如下:
int alloc_chrdev_region(dev_t *dev, \
unsigned baseminor, \
unsigned count, \
const char *name);
dev:输出型参数。保存申请到的设备号
baseminor:次设备号起始地址。alloc_chrdev_region 可以申请一段连续的多个设备号,这 些设备号的主设备号一样,但是次设备号不同,次设备号以 baseminor 为起始地址地址开始递 增。一般 baseminor 为 0,也就是说次设备号从 0 开始。
count:要申请的设备号数量
name:设备名字
int major;
int minor;
dev_t devid;
alloc_chrdev_region(&devid, 0, 1, "test");
major = MAJOR(devid); // 获取主设备号
minor = MINOR(devid); // 获取次设备号
3、释放设备号 —— unregister_chrdev_region
注销字符设备之后要释放掉设备号。无论是静态分配还是动态分配,都是使用该函数注销设备号。函数声明如下:
void unregister_chrdev_region(dev_t from, unsigned count);
from:要释放的设备号。(这里指的是主设备号,并非上面次设备号的起始地址)
count:表示从 from 开始,要释放的设备号数量。