主设备号和次设备号
对字符设备的访问是通过文件系统内的设备名称(设备文件)进行的,位于/dev目录下
一个设备包含主设备号和次设备号,主设备号标识设备对应的驱动程序,次设备号确定设备文件所指的设备
个人理解:一个能正常工作的设备包含设备这个硬件和能使设备工作的驱动程序,次设备号就是标识这个硬件的, 而主设备号是标识这个驱动程序的,主设备号和次设备号唯一确定这个能正常工作的设备。访问/dev下的设备文件,系统就知道调用哪个驱动程序操作哪个硬件
设备编号的内部表达
dev_t类型(<linux/types.h>中定义)用来保存设备编号,包括主设备号和次设备号
获取主设备号用MAJOR(dev_t dev);
获取次设备号用MINOR(dev_t dev);
相反,将主设备号和次设备号转换成dev_t类型,则使用:
MKDEV(int major, int minor);
分配和释放设备编号
在建立一个字符设备之前,我们的驱动程序首先要做的就是使用下面函数(<linux/fs.h>中声明)获得一个或多个设备编号
第一种方式:int register_chrdev_region(dev_t first, unsigned int count, char *name);
这种方式是提前我们知道所需要的设备编号,那么它会工作得很好,
但是我们经常不知道设备将要使用哪些主设备号,则使用下种方式
第二种方式:int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
一旦分配了设备号,就可以从/proc/devices中读取到
不管使用哪种方式,使用结束后都应释放这些设备编号,通常在清除函数中做,使用如下函数
void unregister_chrdev_region(dev_t first, unsigned int count);
分配了设备编号,驱动程序还需要将它们和内部函数连接起来,这些函数用来实现设备的操作
字符设备的注册(分配、初始化和注册)
内核内部使用struct cdev结构来表示字符设备。在内核调用设备的操作之前,必须先分配并注册一个或者多个上述结构
代码应该包含这个<linux/cdev.h>,其中定义了这个结构及与其相关的一些辅助函数
有两种方式分配和初始化上述结构
1、如果作者打算在运行时获取一个独立的cdev结构,则
struct cdev *my_cdev = cdev_alloc();
my_cdev->ops = &my_fops;
2、如果将cdev结构嵌入到自己的设备特定结构中,则用下面代码来初始化已分配到的结构
void cdev_init(struct cdev *cdev, struct file_operations *fops);
分配和初始化结束后,需要做的就是通过下面调用告诉内核该结构的信息:应该就是将inode结构的是i_cdev字段指向该分配到的结构
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
dev是cdev结构,num是该设备对应的第一个设备编号,count是应该和该设备关联的设备编号的数量,经常取1
移除一个字符设备时,使用
void cdev_del(struct cdev *dev);