在Linux内核中用cdev结构体来表示一个字符设备,cdev的定义在linux/Cdev.h中:
struct cdev {
struct kobject kobj; //内嵌的kobject
struct module *owner; //指向实现驱动程序的模块(如果有的话)
const struct file_operations *ops; //指向驱动程序的文件操作表
struct list_head list; //与字符设备对应的设备文件的链表头
dev_t dev; //驱动的设备号
unsigned int count; //设备号的范围
};
该结构体的dev成员定义了设备号。Linux的设备管理是和文件系统紧密结合的,各种设备都以文件的形式存放在/dev目录下,称为设备文件。应用程序可以打开、关闭和读写这些设备文件,完成对设备的操作,就像操作普通的数据文件一样。为了管理这些设备,系统为设备编了号,每个设备号又分为主设备号和次设备号。主设备号用来区分不同种类的设备,而次设备号用来区分同一类型的多个设备。使用ll命令查看/dev目录下的内容,可看到同下面类型的输出:
其中tty是设备名称。5, 0 分别是主设备号和次设备号。主设备号标识设备对应的驱动。次设备号由内核使用,用于确定设备文件所指的设备。
在内核中用dev_t类型来保存设备号。在Linux内核的2.6版本中,dev_t是一个32位的数,其中12为用来表示主设备号,而其余的20位用来表示次设备号。
Dev_t 类型:
//<linux/types.h>
typedef __u32 __kernel_dev_t;
typedef __kernel_dev_tdev_t;
我们的代码不应该对设备编号的组织做任何假定,而应该始终使用<linux/kdev_t.h>中定义的宏来操作设备号。
MAJOR(dev_t dev); //由dev_t类型变量中解析出主设备号
MINOR(dev_t dev); //由dev_t类型变量中解析出次设备号
MKDEV(int major, int minor); //由主设备号和次设备号生成dev_t变量
在创建一个字符设备之前,驱动程序首先要做的就是申请设备号。有两个函数可以为字符设备分配设备号:
int register_chrdev_region(dev_t from, unsigned count, const char *name);
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);
register_chrdev_region函数的三个参数:from---请求分配的设备号的起始值。count---请求的设备号的个数。name---所申请的设备号对应的驱动程序名称。同大部分的内核函数一样,该函数在分配成功时返回0,在错误的情况下将返回一个负的错误码。
alloc_chrdev_region函数的四个参数:dev---指向输出的参数,在成功完成后将保存已分配范围的第一个编号。Baseminor---指定被请求的第一个次设备号。Count和name同register_chrdev_region函数是一样的。该函数的主设备号是内核动态分配的。
由于内核已经将部分设备号分配给了一些常见设备(可在源码中Documentation/devices.txt文件中查。并且也不知道将要运行驱动程序的主机上那些设备号已经被分配了。为了避免可能造成的冲突,我们应该尽量采用alloc_chrdev_region来申请设备号。
设备号也是属于一种系统资源,当不在需要设备号时需要进行释放。可以通过下面的函数释放设备号:
void unregister_chrdev_region(dev_t from, unsigned count);
通常在模块的清除函数中调用unregister_chrdev_region。
下面列出了通常的设备号申请代码:
#define MEMDEV_MAJOR 0
static int memdev_major = MEMDEV_MAJOR;
dev_t devno;
…
if (memdev_major) {
devno = MKDEV(memdev_major, 0);
ret = register_chrdev_region(devno, 1 , "memdev");
} else {
ret = alloc_chrdev_region(&devno, 0, 1, "memdev");
memdev_major = MAJOR(devno);
}
[1].《Linux设备驱动程序》第三版 Jonathan Corbet etc. 魏永明等译 中国电力出版社
[2].《深入理解Linux内核》第三版 Daniel P.Bovet etc. 陈莉君等译 中国电力出版社
[3].《Linux设备驱动开发详解》第二版 宋宝华 人民邮电出版社