Linux驱动开发之设备号
2021-07-06
关键字:主设备号、次设备号
1、什么是设备号
设备号是Linux驱动开发中的术语。
Linux规定每一个字符设备或块设备都必须拥有一个专属设备号。要想在Linux平台开发驱动程序,申请设备号就是开发过程的第一步,只有有了设备号,才能向系统注册设备。
一个设备号由以下两个模块组成:
1、主设备号;
2、次设备号;
主设备号用以表示一个驱动程序的种类。如:USB、显示器、鼠标等。
次设备号用以表示此种类下具体的设备。如:第n个USB接口、第n个显示屏、第n个鼠标等。
主设备号是抽象的事物种类,次设备号则是具象的实体设备。
在 /proc/devices 文件中记载着系统中所有已注册的主设备号及其注册名称。
设备号占32位的宽度。其中主设备号占高12位,次设备号占低20位。不过虽然主设备号的宽度长达12位,实际上在Linux系统中有效值范围仅为 1 ~ 255。
2、设备号相关的接口
虽然我们知道主设备号和次设备号的具体位置,但是还是应该以系统提供的接口来拆分和组合主次设备号。
在Linux内核中,设备号被描述为 dev_t 类型,如下所示:
typedef u_long dev_t;
这个类型的定义隐藏的很深,不必去纠结它的实际定义头文件。我们在开发驱动过程中只需要引入kdev_t.h头文件就可以使用此类型的了:
./kernel/include/linux/kdev_t.h
同时,kdev_t.h头文件中还定义了拆分和组合主次设备号的宏,简要概括如下:
MAJOR(dev_t) //从设备号中将主设备号拆分出来 MINOR(dev_t) //从设备号中将次设备号拆分出来 MKDEV(major, minor) //将主设备号和次设备号组合成设备号
3、静态注册
第1节有提到过:必须持有设备号才能向系统注册设备。而设备号是一个整数,所以理论上我们可以随意“捏造”一个设备号用以向系统注册我们的设备。这种“捏造”设备号以注册设备的形式就被称为“静态注册”方式。
不过这里有一个前提条件:尽量不要和已有的设备号冲突,否则可能会导致设备工作不正常。一般可以在内核源码的 documentation/devices.txt 中看到所有已被注册使用的设备号,我们按需选择一个没被占用的即可。不过如果我们要添加的设备的种类就是系统中已有的种类,那一般我们只需要注册次设备号不要冲突就可以了。
静态注册的方式需要注意的点太多,徒增开发难度。因此应尽量使用动态注册的形式。
4、动态注册
Linux有提供一个动态分配设备号的接口,其原型如下所示:
int alloc_chrdev_region(dev_t* devid, unsigned int baseminor, unsigned int count, const char* name);
参数 devid 作为输出参数使用。
参数 baseminor 表示次设备号起始值。按需设置即可。
参数 count 表示要申请使用的次设备号的数量。
参数 name 表示此设备的描述名称,即在 /proc/devices 中看到的名称。
返回值0表示申请成功。
与动态注册相对的是释放接口。Linux中的设备号是交由系统托管的。如果某驱动程序在运行过程中动态申请了某设备号,但是在卸载时没有释放,则该设备号仍旧存活于系统中。释放设备号的接口原型如下所示:
void unregister_chrdev_region(dev_t devid, unsigned int count);
参数 devid 表示设备号。
参数 count 即次设备号数量。