一个主设备号是如何支持多个次设备?

Posted 正在起飞的蜗牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个主设备号是如何支持多个次设备?相关的知识,希望对你有一定的参考价值。

1、主次设备号

参考博客:《字符设备驱动详解(主次设备号、注册/卸载字符设备驱动、创建设备节点、地址映射)》

2、次设备号介绍

(1)在老的驱动程序里是不需要次设备号的,在老版内核中注册驱动用register_chrdev()函数,只需要传入主设备号,次设备号默认是0;
(2)后面的驱动注册函数,需要通过alloc_chrdev_region()函数先申请设备号,其中就包括第一个设备号和次设备号的个数;
(3)主设备号和次设备号共同表示一个设备驱动;

3、使用次设备号的好处

(1)共享主设备号的驱动程序一般都是一类设备,这样方便管理和理解;
(2)某些时候不同的设备是可以共享同一个驱动程序,只需要在驱动程序中对次设备进行区分,这样多个设备就只占用一个主设备号;比如串口驱动,不同的串口操作方法都是一样的,不一样的是串口对应的寄存器基地址,如果我们能在驱动程序中通过次设备号知道此次是操作哪个串口,然后就使用对应的寄存器基地址,就可以实现多个串口共用一个驱动程序;
(3)多个设备共享一个主设备号,通过次设备号区分,可以节省主设备号。在内核中,字符设备驱动都注册到chrdevs全局变量中,这是一个结构体指针数组,总共有255个成员,也就是说内核最多支持255个字符设备驱动;

4、驱动程序如何区分次设备号

4.1、创建设备节点

(1)创建设备节点会指定主次设备号,通过主次设备号就可以找到对应的驱动程序;
(2)(参考博客:《字符设备驱动程序自动创建设备节点详解》《设备节点如何与设备驱动关联》

4.2、上层应用程序打开设备节点

//驱动代码中struct file_operations结构体的open函数指针
int open(struct inode *, struct file *)

	//将描述字符设备的struct cdev结构体传给struct file结构体,后续操作会用到
	file->private_data = inode->i_cdev;
	return 0;

(1)在创建设备节点时指定了主次设备号,所以open函数打开设备节点时,struct inode结构体中就报错了主次设备号和对应的struct cedv结构体指针;
(2)只有在open设备节点时才会传入struct inode结构体指针和struct file结构体指针,但是在struct file结构体指针中时不包含主次设备号信息的;
(3)struct file结构体中有个private_data 变量,时专门用来存私有数据的,我们可以在open打开时将主次设备号保存到private_data 变量中;

4.3、应用程序读写驱动程序

//驱动代码中struct file_operations结构体的read函数指针
ssize_t read(struct file *file, char __user *buf, size_t size, loff_t *pos)

	struct cdev *cd;
	unsigned int minor;

	//得到open函数打开设备节点时保存的数据
	cd = (struct cdev *)file->private_data;
	
	//获得次设备号
	minor = MINOR(cd->dev)
	
	//根据不同的次设备进行操作
	······
	
	return size;

(1)应用程序在调用read、write等操作驱动程序函数时,都会把struct file结构体传入,在open时我们已经把字符设备驱动的相关信息保存到struct file结构体的private_data中;
(2)在操作前去解析struct file结构体的private_data变量,得到次设备号,有了次设备号后续就可以进行差别的操作;
补充:上面只介绍了read函数,但是其他的操作函数也是一样的,都会传入struct file结构体指针;

以上是关于一个主设备号是如何支持多个次设备?的主要内容,如果未能解决你的问题,请参考以下文章

主次设备号的应用

linux 查看主次设备号

Linux的设备和设备号是指啥

主次设备号 Device Major and Minor Numbers

为啥在/dev目录下不能生成spidev1.0的设备文件

为啥linux在/dev目录中使用ls -l命令看到有的设备没有主设备号