【问】
linux device driver 书中的scull是干什么的? – 知乎
“
前面几章给出了一堆scull的东西,貌似用内存模拟一个设备开始讲,没怎么搞清楚是什么,准备继续往下看,但是一涉及代码没看明白里面提到的quantum和qset指的是什么意思,为什么要弄个这个像分页一样的东西.
那为什么要搞成量子和量子集呢?直接一片连续的量子不行么. ”
【答】
去搜了搜:
linux device driver scull quantum qset
scull quantum qset
what is quantum qset
找到一些相关内容:
看了些解释后,稍微有点点明白了:
“前面几章给出了一堆scull的东西,貌似用内存模拟一个设备开始讲,没怎么搞清楚是什么”
其实我也没搞懂。包括最初接触和学习Linux驱动的时候也大略看了看这部分的内容。
大概知道ldd中是用这个scull为例来解释驱动模型的。
现在的话,我的评价是:
其实我个人也是觉得,对于想要搞懂Linux驱动模型,其实需要先把驱动的总体概况解释清楚后,然后再去解释如何套用Linux的框架模型去实现驱动功能。
如此才更加容易解释清楚Linux驱动模型。
直接以类似于scull的例子来说明,尤其对于我们中国很多开发者,本身缺乏对于Linux本身和驱动这个概念本身不太了解的情况下,是没法很容易的理解Linux驱动框架的。
“准备继续往下看,但是一涉及代码没看明白里面提到的quantum和qset指的是什么意思,为什么要弄个这个像分页一样的东西”
先回答你的此处具体的问题“quantum和qset指的是什么意思”,“那为什么要搞成量子和量子集呢?直接一片连续的量子不行么. ”
我的理解是:
想要理解你说的这两个问题,先要了解scull本身这个驱动实例所要实现的目的:
就像别人已经解释的:
scull==simple character utility for loading localities==区域装载的简单字符工具
scull的目的是为了演示,在Liunx驱动中的字符char设备(与此对应的另外一种叫做块block设备)
的区域装载
->实际上就是演示,以字符设备操作的方式,去支持你的文件读写
->文件的读取或者写入,就会涉及到文件内部存储到物理的存储设备上
->物理存储设备,常见的硬件(不论是SATA还是SSD等等),但是此处为了更加方便演示,以更简单的内存RAM为存储空间来演示
->所以就设计到,保存你写入的文件到存储设备RAM上
->对应的,你读取你之前保存的文件时,也就是从RAM上把文件数据读出去
->所以,此时就需要采取一定的策略,即方法,方式,去管理,去操作内存RAM
(而此处由于scull的目的只是为了教你理解Liunx驱动模型,重点不在内存管理上
所以就只是简单的采用了直接调用内核的一些内存管理的函数kmalloc和kfree去申请和释放内存
没有去花更多的精力和写更多代码去优化,没有去实现更加高效率的内存的申请和释放)
->而此处用于演示文件读写等简单操作,且又想变成(很傻的)去限制一个用户操作此scull驱动,去读写文件时,去限定文件大小
->比如,要求使用scull驱动的用户,保存文件最大不能超过100MB
->如果设计出这样一个,对于文件大小,读写数据的大小有限制的驱动,那也显得驱动设计者太傻了
->在如此考虑的前提下,那么底层内存分配就要实现,既要相对分配内存的销量不能太低,也要保证方便的支持很大或者很小的文件,所及时申请到对应的内存
->很自然的,内部实现,就会设计到,用一小块内存为一个基本单元,然后每次分配,根据文件大小,决定分几块。
->比如基本单元是4KB,要保存一个10KB小文件,那么只需要3个单元即可。而要保存一个10MB的文件,则需要10*1000/4=2500个单元。
->基于此考虑,如果底层的内存分配的实现机制,是每次分配一块连续的RAM的话,小文件还好申请到,但是大文件申请如此大的空间就会容易失败,因为内存中存在连续的大空间的机会不太多
->即:连续的空间(你所说的连续的量子)就很难一次性成功的申请到了
->所以此处设计了一个链表,每个链表节点是个结构体scull_qset,然后每个结构体都包含了指针指向具体分配出来的空间
->链表的优势就是可以无限扩充,可大可小,不论是小文件还是大文件都能很方便的支持
->而指针指向的每个单元,scull作者就起了个名字叫做quantum,以及把这些集合成为qset
->你要是scull的作者,你也可以换个你喜欢的名字,比如叫做cell单元,那么上述名字分别就是:
cell,cset==cell set,scull_cset
了。
这就是,为什么要搞成量子和量子集的原因,因为先是要有基本的单元,其次是用链表连接起来这些基本的单元,然后组成一个集合。
至于名字叫做量子,那是作者高兴起啥名就叫啥名。
->
其实说到底,都早已偏离了问题的本质:
写scull的目的,即不是用于演示内存分配(作者也专门强调了这一点),更不是去关于内存分配的策略和细节(采用链表而不是连续空间),甚至底层变量的命名(为何叫做量子和量子集),而是为了演示Linux驱动模型。
->但是的确就是如此做法,早已让本来就对于Linux驱动模型不了解的人,越看越觉得复杂,越糊涂了。。
【关于如何写Linux驱动】
我只能说,还是等我哪天有空去写解释Linux驱动的教程,尝试把问题说的明白。或许你就会更加明白驱动是啥,Linux驱动是啥,如何写,而无需纠结操心这样的细节了。
PS:估计短期内都忙得没空。。。
在写教程之前,先尝试用一段话解释大概逻辑:
先要搞懂Linux驱动所要驱使能使其动起来,运行起来的对应的设备的工作原理
比如USB,Nand Flash,RS232,SPI,I2C
要搞懂这些协议或技术规范本身,要求该设备是如何工作的:
需要有哪些硬件模块做哪些事情
剩下的是拿着这个硬件模块,写软件代码又是去操作哪些事情
最终才是用软件驱动硬件工作,之所以这样才叫做驱动,用软件代码,驱使硬件,按照协议规范所规定的方式去运行,去工作
而这其中的软件部分,要先记住目的:让硬件工作
工作的意思是:
往往都可以归结于:
先初始化硬件,配置参数
再执行数据的读取read和写入wrte,即接收receive/发送send数据
而在这个初始化和数据收发的过程,往往是软件硬件协同工作
所以要看懂该协议的规定和细节是什么
然后看懂了硬件做了哪些事情:这些无需你软件代码操心
然后再去看软件代码做了哪些事情
而软件代码要做的事情:理论上来说,都需要你全部实现,写出完整代码的
但是在Liunx操作系统下面,Linux系统框架内部,帮你做了,相对来说,是不同厂商的不同设备所通用的,符合该硬件所涉及的协议的通用的部分,
而你真正要实现的,其实只是涉及到最底层的,操作你自己的设备的那些函数而已
那些底层的,和你自己设备相关的函数,才是去真正的初始化和配置你自己的设备,然后执行数据手法,才叫做你的设备的驱动
简言之:
驱动,意思是写代码==软件,驱使,硬件,去动==工作==干活==往往都是数据的接受和发送而已
即通过软件代码让硬件干活
你要写的驱动,往往只是:
在硬件所涉及的协议规范,决定了其工作方式和流程,逻辑
而写Linux驱动,其实就是:
先看懂逻辑和框架:搞懂除去Linux系统相关的驱动框架已经帮你实现好了的该协议的多数通用的逻辑和流程
然后再去实现,和你自己的设备相关的,(硬件初始化工作之外的)数据的接收和发送部分的代码而已。
目前已经写了一个特定技术的教程,供参考:
以后还会整理出相关教程的。