中暑虚脱

注册

 

发新话题 回复该主题

字符设备打开的时候发生了什么以及一些思考 [复制链接]

1#

linux驱动等于单片机操作+linux各个子系统架构+操作系统,但是学习的时候要把重心放在架构和操作系统上面,这样驱动设计得更好。我一直不满足于在产品侧当一个看代码的bsp驱动工程师,有朝一日我想去大厂,去当芯片端的bsp驱动工程师,让别人用我设计的驱动。因此,我真就只遵循套路来写一些简单的设备驱动就行了吗?

重新学习字符设备的时候发现了第一次学习没有思考的几个问题:

总的来看当我们打开一个设备节点,系统发生了什么?如何和我的驱动操作集关联?想要一个驱动兼容同类的设备时候,次设备号扮演了什么角色?如何去设置cdev?cdev需要多少个?

以上问题并不能直接解答,先看看我们是怎么把一个字符设备以及他的操作集加到系统中的。

设备号的管理

众所周知,设备驱动中有个很重要的概念叫设备号,一个32位设备号分为主设备号和次设备号,高20位是主设备号,次设备号的低12位。主设备号对应的是某个驱动程序.ko,次设备号标识这个驱动管理下的各种同类设备。

我使用alloc_chrdev_region函数来分配和注册设备号

intalloc_chrdev_region(dev_t*dev,unsignedbaseminor,unsignedcount,constchar*name)#第一个参数是你传入的一个变量用于保存系统分配的设备号#第二、三个参数是以次设备号开始申请多少个次设备号#第四个参数是管理这组设备的一个管理员名字

上面说的管理员实际是结构体char_device_struct。

然后现在啥也别想char_device_struct是什么了,全都抛弃。系统中有个管理设备号的数组:chardevs[]。里面每一个元素都是一个char_device_struct指针。

比如我这样分配

alloc_chrdev_region(imx6ull_led_beep.device_num,0,2,"led_beep");

那么对应的状况就会是这样的

为什么major是1或者?因为如果要找的话,是通过求模找的比如1%等于1,%也等于1。如果同时1和主设备号同时存在,那么也可以加到chrdevs[1]下面来管理,按照major大小从小到大链表排列。比如下面这样

这个结论就是:设备号是通过chedevs数组管理的。但是这并没有接近我思考的问题的核心。

字符设备cdev的管理

字符设备驱动中最重要的就是cdev和它的操作集。那它是如何管理的。

涉及两个函数:

voidcdev_init(structcdev*cdev,conststructfile_operations*fops)intcdev_add(structcdev*p,dev_tdev,unsignedcount)

cdev_init就是绑定cdev和操作集,cdev_add就是加入到管理中来。

cdev的管理是由cdev_map指针来管理的,指向一个structkobj_map

比如我向系统这样增加

cdev_init(imx6ull_led_beep.cdev,imx6ull_led_beep_fops);cdev_add(imx6ull_led_beep.cdev,imx6ull_led_beep.device_num,2);或者cdev_init(imx6ull_led_beep.cdev,imx6ull_led_beep_fops);cdev_add(imx6ull_led_beep.cdev,imx6ull_led_beep.device_num,1);cdev_add(imx6ull_led_beep.cdev,imx6ull_led_beep.device_num+1,1);#以上两种方法一样的,为什么呢?因为imx6ull_led_beep.device_num#和imx6ull_led_beep.device_num+1都是同一个major

对应的状况是这样:

因此可以得出结论:一个驱动(主设备号)下,只设置一个cdev也能够管理多个同类设备,只要你认为同类设备都能用同一个操作集。但是注意cdev注册和设备号管理并没有关系!

注意:cdev_map同样是根据求模取得位置的,和上面chrdevs一样,但是这个不要太

分享 转发
TOP
发新话题 回复该主题