高级字符驱动操作说明_第1页
高级字符驱动操作说明_第2页
高级字符驱动操作说明_第3页
高级字符驱动操作说明_第4页
高级字符驱动操作说明_第5页
已阅读5页,还剩79页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 HYPERLINK 更多企业业学院:中小企企业管理理全能版版183套套讲座+897700份份资料总经理理、高层层管理49套讲讲座+1163888份资料中层管管理学院院46套讲讲座+660200份资料国学智智慧、易易经46套讲讲座人力资资源学院院56套讲讲座+2271223份资料各阶段段员工培培训学院院77套讲讲座+ 3244份资料员工管管理企业业学院67套讲讲座+ 87220份资料工厂生生产管理理学院52套讲讲座+ 139920份份资料财务管管理学院院53套讲讲座+ 179945份份资料销售经经理学院院56套讲讲座+ 143350份份资料销售人人员培训训学院72套讲讲座+ 48779份资料(

2、20008-009-228 116:228) 分类: 第 6 章 高高级字符符驱动操操作在第 33 章, 我们们建立了了一个完完整的设设备驱动动, 用用户可用用来写入入和读取取. 但但是一个个真正的的设备常常常提供供比同步步读和写写更多的的功能. 现在在我们已已装备有有调试工工具如果果发生错错误, 并且一一个牢固固的并发发的理解解来帮助助避免事事情进入入错误- 我我们可安安全地前前进并且且创建一一个更高高级的驱驱动.本章检查查几个你你需要理理解的概概念来编编写全特特性的字字符设备备驱动. 我们们从实现现 iooctll 系统统调用开开始, 它是用用作设备备控制的的普通接接口. 接着我我们进入入

3、各种和和用户空空间同步步的方法法; 在在本章结结尾, 你有一一个充分分的认识识对于如如何使进进程睡眠眠(并且且唤醒它它们), 实现现非阻塞塞的 II/O, 并且且通知用用户空间间当你的的设备可可用来读读或写. 我们们以查看看如何在在驱动中中实现几几个不同同的设备备存取策策略来结结束.这里讨论论的概念念通过 scuull 驱动的的几个修修改版本本来演示示. 再再一次, 所有有的都使使用内存存中的虚虚拟设备备来实现现, 因因此你可可自己试试验这些些代码而而不必使使用任何何特别的的硬件. 到此此为止, 你可可能在想想亲手使使用真正正的硬件件, 但但是那将将必须等等到第 9 章章.6.1.iocctl

4、 接口大部分驱驱动需要要 - 除了了读写设设备的能能力 - 通通过设备备驱动进进行各种种硬件控控制的能能力. 大部分分设备可可进行超超出简单单的数据据传输之之外的操操作; 用户空空间必须须常常能能够请求求, 例例如, 设备锁锁上它的的门, 弹出它它的介质质, 报报告错误误信息, 改变变波特率率, 或或者自我我销毁. 这些些操作常常常通过过 iooctll 方法法来支持持, 它它通过相相同名子子的系统统调用来来实现.在用户空空间, iocctl 系统调调用有下下面的原原型:int iocctl(intt fdd, uunsiigneed llongg cmmd, .); 这个原型型由于这这些点而

5、而凸现于于 Unnix 系统调调用列表表, 这这些点常常常表示示函数有有数目不不定的参参数. 在实际际系统中中, 但但是, 一个系系统调用用不能真真正有变变数目的的参数. 系统统调用必必须有一一个很好好定义的的原型, 因为为用户程程序可存存取它们们只能通通过硬件件的门门. 因此, 原型型中的点点不表示示一个变变数目的的参数, 而是是一个单单个可选选的参数数, 传传统上标标识为 chaar *arggp. 这些点点在那里里只是为为了阻止止在编译译时的类类型检查查. 第第 3 个参数数的实际际特点依依赖所发发出的特特定的控控制命令令( 第第 2 个参数数 ). 一些些命令不不用参数数, 一一些用一

6、一个整数数值, 以及一一些使用用指向其其他数据据的指针针. 使使用一个个指针是是传递任任意数据据到 iiocttl 调调用的方方法; 设备接接着可与与用户空空间交换换任何数数量的数数据.iocttl 调调用的非非结构化化特性使使它在内内核开发发者中失失宠. 每个 iocctl 命令, 基本本上, 是一个个单独的的, 常常常无文文档的系系统调用用, 并并且没有有方法以以任何类类型的全全面的方方式核查查这些调调用. 也难于于使非结结构化的的 iooctll 参数数在所有有系统上上一致工工作; 例如, 考虑虑运行在在 322-位模模式的一一个用户户进程的的 644-位 系统. 结果果, 有有很大的的

7、压力来来实现混混杂的控控制操作作, 只只通过任任何其他他的方法法. 可可能的选选择包括括嵌入命命令到数数据流(本章稍稍后我们们将讨论论这个方方法)或或者使用用虚拟文文件系统统, 要要么是 syssfs 要么是是设备特特定的文文件系统统. (我们将将在 114 章章看看 syssfs). 但但是, 事实是是 iooctll 常常常是最容容易的和和最直接接的选择择,对于于真正的的设备操操作.iocttl 驱驱动方法法有和用用户空间间版本不不同的原原型:int (*iiocttl) (sttrucct iinodde *inoode, sttrucct ffilee *ffilpp, uunsiig

8、need iint cmdd, uunsiigneed llongg arrg);inodde 和和 fiilp 指针是是对应应应用程序序传递的的文件描描述符 fd 的值, 和传传递给 opeen 方方法的相相同参数数. ccmd 参数从从用户那那里不改改变地传传下来, 并且且可选的的参数 argg 参数数以一个个 unnsiggnedd loong 的形式式传递, 不管管它是否否由用户户给定为为一个整整数或一一个指针针. 如如果调用用程序不不传递第第 3 个参数数, 被被驱动操操作收到到的 aarg 值是无无定义的的. 因因为类型型检查在在这个额额外参数数上被关关闭, 编译器器不能警警告你如

9、如果一个个无效的的参数被被传递给给 iooctll, 并并且任何何关联的的错误将将难以查查找.如果你可可能想到到的, 大部分分 iooctll 实现现包括一一个大的的 swwitcch 语语句来根根据 ccmd 参数, 选择择正确的的做法. 不同同的命令令有不同同的数值值, 它它们常常常被给予予符号名名来简化化编码. 符号号名通过过一个预预处理定定义来安安排. 定制的的驱动常常常声明明这样的的符号在在它们的的头文件件中; scuull.h 为为 scculll 声明明它们. 用户户程序必必须, 当然, 包含含那个头头文件来来存取这这些符号号.6.1.1.选择 iocctl 命令在为 iioct

10、tl 编编写代码码之前, 你需需要选择择对应命命令的数数字. 许多程程序员的的第一个个本能的的反应是是选择一一组小数数从0或或1开始始, 并并且从此此开始向向上. 但是, 有充充分的理理由不这这样做. iooctll 命令令数字应应当在这这个系统统是唯一一的, 为了阻阻止向错错误的设设备发出出正确的的命令而而引起的的错误. 这样样的不匹匹配不会会不可能能发生, 并且且一个程程序可能能发现它它自己试试图改变变一个非非串口输输入系统统的波特特率, 例如一一个 FFIFOO 或者者一个音音频设备备. 如如果这样样的 iiocttl 号号是唯一一的, 这个应应用程序序得到一一个 EEINVVAL 错误

11、而而不是继继续做不不应当做做的事情情.为帮助程程序员创创建唯一一的 iiocttl 命命令代码码, 这这些编码码已被划划分为几几个位段段. LLinuux 的的第一个个版本使使用 116-位位数: 高 88 位是是关联这这个设备备的魔魔数, 低 8 位位是一个个顺序号号, 在在设备内内唯一. 这样样做是因因为 LLinuus 是是无能能的(他自己己的话); 一一个更好好的位段段划分仅仅在后来来被设想想. 不不幸的是是, 许许多驱动动仍然使使用老传传统. 它们不不得不: 改变变命令编编码会破破坏大量量的二进进制程序序,并且且这不是是内核开开发者愿愿意见到到的.根据 LLinuux 内内核惯例例来

12、为你你的驱动动选择 iocctl 号, 你应当当首先检检查 iinclludee/assm/iiocttl.hh 和 Doccumeentaatioon/iiocttl-nnumbber.txtt. 这这个头文文件定义义你将使使用的位位段: typpe(魔魔数), 序号号, 传传输方向向, 和和参数大大小. iocctl-nummberr.txxt 文文件列举举了在内内核中使使用的魔魔数, 因因此你将将可选择择你自己己的魔数数并且避避免交叠叠. 这这个文本本文件也也列举了了为什么么应当使使用惯例例的原因因.定义 iiocttl 命命令号的的正确方方法使用用 4 个位段段, 它它们有下下列的含含

13、义. 这个列列表中介介绍的新新符号定定义在 .typee 魔数. 只是选选择一个个数(在在参考了了 iooctll-nuumbeer.ttxt之之后)并并且使用用它在整整个驱动动中. 这个成成员是 8 位位宽(_IOCC_TYYPEBBITSS). numbber 序(顺序序)号. 它是是 8 位(_IOCC_NRRBITTS)宽宽. direectiion 数据传送送的方向向,如果果这个特特殊的命命令涉及及数据传传送. 可能的的值是 _IOOC_NNONEE(没有有数据传传输), _IIOC_REAAD, _IOOC_WWRITTE, 和 _IOCC_REEAD|_IOOC_WWRITTE

14、(数据在在2个方方向被传传送). 数据据传送是是从应用用程序的的观点来来看待的的; _IOCC_REEAD 意思是是从设备备读, 因此设设备必须须写到用用户空间间. 注注意这个个成员是是一个位位掩码, 因此此 _IIOC_REAAD 和和 _IIOC_WRIITE 可使用用一个逻逻辑 AAND 操作来来抽取.sizee 涉及到的的用户数数据的大大小. 这个成成员的宽宽度是依依赖体系系的, 但是常常常是 13 或者 14 位. 你可为为你的特特定体系系在宏 _IOOC_SSIZEEBITTS 中中找到它它的值. 你使使用这个个 siize 成员不不是强制制的 - 内核核不检查查它 - 但但是它是

15、是一个好好主意. 正确确使用这这个成员员可帮助助检测用用户空间间程序的的错误并并使你实实现向后后兼容, 如果果你曾需需要改变变相关数数据项的的大小. 如果果你需要要更大的的数据结结构, 但是, 你可可忽略这这个 ssizee 成员员. 我我们很快快见到如如何使用用这个成成员.头文件 , 它包含含在 中, 定义宏宏来帮助助建立命命令号, 如下下: _IO(typpe,nnr)(给没有有参数的的命令), _IORR(tyype, nrre, dattatyype)(给从从驱动中中读数据据的), _IIOW(typpe,nnr,ddataatyppe)(给写数数据), 和 _IOOWR(typpe,

16、nnr,ddataatyppe)(给双向向传送). ttypee 和 nummberr 成员员作为参参数被传传递, 并且 sizze 成成员通过过应用 sizzeoff 到 dattatyype 参数而而得到.这个头文文件还定定义宏, 可被被用在你你的驱动动中来解解码这个个号: _IOOC_DDIR(nr), _IOCC_TYYPE(nr), _IOCC_NRR(nrr), 和 _IOCC_SIIZE(nr). 我我们不进进入任何何这些宏宏的细节节, 因因为头文文件是清清楚的, 并且且在本节节稍后有有例子代代码展示示.这里是一一些 iiocttl 命命令如何何在 ssculll 被被定义的的.

17、 特特别地, 这些些命令设设置和获获得驱动动的可配配置参数数./* UUse k ass maagicc nuumbeer */#deffinee SCCULLL_IOOC_MMAGIIC k/* PPleaase usee a diffferrentt 8-bitt nuumbeer iin yyourr coode */#deffinee SCCULLL_IOOCREESETT _IIO(SSCULLL_IIOC_MAGGIC, 0)/* * SS meeanss SSet thhrouugh a pptr, * TT meeanss TTelll ddireectlly wwithh t

18、hhe aarguumennt vvaluue * GG meeanss GGet: rreplly bby ssetttingg thhrouugh a ppoinnterr * QQ meeanss QQuerry: reespoonsee iss onn thhe rretuurn vallue * XX meeanss eeXchhangge: swwitcch GG annd SS attomiicallly * HH meeanss ssHifft: swwitcch TT annd QQ attomiicallly */#deffinee SCCULLL_IOOCSQQUANNT

19、UMM _IIOW(SCUULL_IOCC_MAAGICC, 11, iint)#deffinee SCCULLL_IOOCSQQSETT _IIOW(SCUULL_IOCC_MAAGICC, 22, iint)#deffinee SCCULLL_IOOCTQQUANNTUMM _IIO(SSCULLL_IIOC_MAGGIC, 3)#deffinee SCCULLL_IOOCTQQSETT _IIO(SSCULLL_IIOC_MAGGIC, 4)#deffinee SCCULLL_IOOCGQQUANNTUMM _IIOR(SCUULL_IOCC_MAAGICC, 55, iint)#def

20、finee SCCULLL_IOOCGQQSETT _IIOR(SCUULL_IOCC_MAAGICC, 66, iint)#deffinee SCCULLL_IOOCQQQUANNTUMM _IIO(SSCULLL_IIOC_MAGGIC, 7)#deffinee SCCULLL_IOOCQQQSETT _IIO(SSCULLL_IIOC_MAGGIC, 8)#deffinee SCCULLL_IOOCXQQUANNTUMM _IIOWRR(SCCULLL_IOOC_MMAGIIC, 9, intt)#deffinee SCCULLL_IOOCXQQSETT _IIOWRR(SCCULLL_

21、IOOC_MMAGIIC,110, intt)#deffinee SCCULLL_IOOCHQQUANNTUMM _IIO(SSCULLL_IIOC_MAGGIC, 111)#deffinee SCCULLL_IOOCHQQSETT _IIO(SSCULLL_IIOC_MAGGIC, 122)#deffinee SCCULLL_IOOC_MMAXNNR 114真正的源源文件定定义几个个额外的的这里没没有出现现的命令令.我们选择择实现 2 种种方法传传递整数数参数: 通过过指针和和通过明明确的值值(尽管管, 由由于一个个已存在在的惯例例, iiocllt 应应当通过过指针交交换值). 类类似地,

22、 2 种方法法被用来来返回一一个整数数值:通通过指针针和通过过设置返返回值. 这个个有效只只要返回回值是一一个正的的整数; 如同同你现在在所知道道的, 在从任任何系统统调用返返回时, 一个个正值被被保留(如同我我们在 reaad 和和 wrritee 中见见到的), 而而一个负负值被看看作一个个错误并并且被用用来在用用户空间间设置 errrno.excchannge和sshifft操操作对于于 scculll 没有有特别的的用处. 我们们实现excchannge来显示示驱动如如何结合合独立的的操作到到单个的的原子的的操作, 并且且shhiftt来连连接ttelll和queery. 有有时需要要

23、象这样样的原子子的测试试-和-设置操操作, 特别地地, 当当应用程程序需要要设置和和释放锁锁.命令的明明确的序序号没有有特别的的含义. 它只只用来区区分命令令. 实实际上, 你甚甚至可使使用相同同的序号号给一个个读命令令和一个个写命令令, 因因为实际际的 iiocttl 号号在方方向位位是不同同的, 但是你你没有理理由这样样做. 我们选选择在任任何地方方不使用用命令的的序号除除了声明明中, 因此我我们不分分配一个个返回值值给它. 这就就是为什什么明确确的号出出现在之之前给定定的定义义中. 这个例例子展示示了一个个使用命命令号的的方法, 但是是你有自自由不这这样做.除了少数数几个预预定义的的命令

24、(马上就就讨论), iiocttl 的的 cmmd 参参数的值值当前不不被内核核使用, 并且且在将来来也很不不可能. 因此此, 你你可以, 如果果你觉得得懒, 避免前前面展示示的复杂杂的声明明并明确确声明一一组调整整数字. 另一一方面, 如果果你做了了, 你你不会从从使用这这些位段段中获益益, 并并且你会会遇到困困难如果果你曾提提交你的的代码来来包含在在主线内内核中. 头文文件 是是这个老老式方法法的例子子, 使使用 116-位位的调整整值来定定义 iiocttl 命命令. 那个源源代码依依靠调整整数因为为使用那那个时候候遵循的的惯例, 不是是由于懒懒惰. 现在改改变它可可能导致致无理由由的不

25、兼兼容.6.1.2.返回值值iocttl 的的实现常常常是一一个 sswittch 语句, 基于于命令号号. 但但是当命命令号没没有匹配配一个有有效的操操作时缺缺省的选选择应当当是什么么? 这这个问题题是有争争议的. 几个个内核函函数返回回 -EENIVVAL(Innvallid arggumeent), 它有意意义是因因为命令令参数确确实不是是一个有有效的. POOSIXX 标准准, 但但是, 说如果果一个不不合适的的 iooctll 命令令被发出出, 那那么 -ENOOTTYY 应当当被返回回. 这这个错误误码被 C 库库解释为为设备备的不适适当的 iocctl, 这这常常正正是程序序员需

26、要要听到的的. 然然而, 它仍然然是相当当普遍的的来返回回 -EEINVVAL, 对于于响应一一个无效效的 iiocttl 命命令.6.1.3.预定义义的命令令尽管 iiocttl 系系统调用用最常用用来作用用于设备备, 内内核能识识别几个个命令. 注意意这些命命令, 当用到到你的设设备时, 在你你自己的的文件操操作被调调用之前前被解码码. 因因此, 如果你你选择相相同的号号给一个个你的 iocctl命命令, 你不会会看到任任何的给给那个命命令的请请求, 并且应应用程序序获得某某些不期期望的东东西, 因为在在 iooctll 号之之间的冲冲突.预定义命命令分为为 3 类:可对任何何文件发发出的

27、(常规, 设备备, FFIFOO, 或或者 ssockket) 的那那些.只对常规规文件发发出的那那些.对文件系系统类型型特殊的的那些.最后一类类的命令令由宿主主文件系系统的实实现来执执行(这这是 cchatttr 命令如如何工作作的). 设备备驱动编编写者只只对第一一类命令令感兴趣趣, 它它们的魔魔数是 T. 查查看其他他类的工工作留给给读者作作为练习习; eext22_iooctll 是最最有趣的的函数(并且比比预期的的要容易易理解), 因因为它实实现 aappeend-onlly 标标志和 immmutaablee 标志志.下列 iiocttl 命命令是预预定义给给任何文文件, 包括设设

28、备特殊殊的文件件:FIOCCLEXX 设置 cclosse-oon-eexecc 标志志( CClosse oon EEXecc). 设置这这个标志志使文件件描述符符被关闭闭, 当当调用进进程执行行一个新新程序时时.FIONNCLEEX 清除 cclosse-nno-eexecc 标志志( NNot CLoose on EXeec). 这个个命令恢恢复普通通文件行行为, 复原上上面 FFIOCCLEXX 所做做的. FIOOASYYNC 为这个个文件设设置或者者复位异异步通知知(如同同在本章章中异异步通知知一节节中讨论论的). 注意意直到 Linnux 2.22.4 版本的的内核不不正确地地使

29、用这这个命令令来修改改 O_SYNNC 标标志. 因为两两个动作作都可通通过 ffcnttl 来来完成, 没有有人真正正使用 FIOOASYYNC 命令, 它在在这里出出现只是是为了完完整性.FIOQQSIZZE 这个命令令返回一一个文件件或者目目录的大大小; 当用作作一个设设备文件件, 但但是, 它返回回一个 ENOOTTYY 错误误.FIONNBIOO Noon-BBlocckinng II/O(在阻塞和和非阻塞塞操作一节中中描述). 这这个调用用修改在在 fiilp-f_flaags 中的 O_NNONBBLOCCK 标标志. 给这个个系统调调用的第第 3 个参数数用作指指示是否否这个标

30、标志被置置位或者者清除. (我我们将在在本章看看到这个个标志的的角色). 注注意常用用的改变变这个标标志的方方法是使使用 ffcnttl 系系统调用用, 使使用 FF_SEETFLL 命令令.列表中的的最后一一项介绍绍了一个个新的系系统调用用, ffcnttl, 它看来来象 iiocttl. 事实上上, ffcnttl 调调用非常常类似 iocctl, 它也也是获得得一个命命令参数数和一个个额外的的(可选选地)参参数. 它保持持和 iiocttl 独独立主要要是因为为历史原原因: 当 UUnixx 开发发者面对对控制 I/OO 操作作的问题题时, 他们决决定文件件和设备备是不同同的. 那时,

31、有 iocctl 实现的的唯一设设备是 ttyys, 它解释释了为什什么 -ENOOTTYY 是标标准的对对不正确确 iooctll 命令令的回答答. 事事情已经经改变, 但是是 fccntll 保留留为一个个独立的的系统调调用.6.1.4.使用 iocctl 参数在看 ssculll 驱驱动的 iocctl 代码之之前, 我们需需要涉及及的另一一点是如如何使用用这个额额外的参参数. 如果它它是一个个整数, 就容容易: 它可以以直接使使用. 如果它它是一个个指针, 但是是, 必必须小心心些.当用一个个指针引引用用户户空间, 我们们必须确确保用户户地址是是有效的的. 试试图存取取一个没没验证过过

32、的用户户提供的的指针可可能导致致不正确确的行为为, 一一个内核核 ooops, 系统统崩溃, 或者者安全问问题. 它是驱驱动的责责任来对对每个它它使用的的用户空空间地址址进行正正确的检检查, 并且返返回一个个错误如如果它是是无效的的.在第 33 章, 我们们看了 coppy_ffromm_usser 和 ccopyy_too_usser 函数, 它们们可用来来安全地地移动数数据到和和从用户户空间. 这些些函数也也可用在在 iooctll 方法法中, 但是 iocctl 调用常常常包含含小数据据项, 可通过过其他方方法更有有效地操操作. 开始, 地址址校验(不传送送数据)由函数数 acccess

33、s_ook 实实现, 它定义义在 :int acccesss_okk(innt ttypee, cconsst vvoidd *aaddrr, uunsiigneed llongg siize); 第一个参参数应当当是 VVERIIFY_REAAD 或或者 VVERIIFY_WRIITE, 依据据这个要要进行的的动作是是否是读读用户空空间内存存区或者者写它. adddr 参数持持有一个个用户空空间地址址, ssizee 是一一个字节节量. 例如, 如果果 iooctll 需要要从用户户空间读读一个整整数, sizze 是是 siizeoof(iint). 如如果你需需要读和和写给定定地址, 使

34、用用 VEERIFFY_WWRITTE, 因为它它是 VVERIIRY_REAAD 的的超集.不象大部部分的内内核函数数, aacceess_ok 返回一一个布尔尔值: 1 是是成功(存取没没问题)和 00 是失失败(存存取有问问题). 如果果它返回回假, 驱动应应当返回回 -EEFAUULT 给调用用者.关于 aacceess_ok有有多个有有趣的东东西要注注意. 首先, 它不不做校验验内存存存取的完完整工作作; 它它只检查查看这个个内存引引用是在在这个进进程有合合理权限限的内存存范围中中. 特特别地, acccesss_ook 确确保这个个地址不不指向内内核空间间内存. 第22, 大大部分

35、驱驱动代码码不需要要真正调调用 aacceess_ok. 后面面描述的的内存存存取函数数为你负负责这个个. 但但是, 我们来来演示它它的使用用, 以以便你可可见到它它如何完完成.sculll 源源码利用用了 iiocllt 号号中的位位段来检检查参数数, 在在 swwitcch 之之前:int errr = 0, tmpp;int rettvall = 0;/* * eextrractt thhe ttypee annd nnumbber bittfieeldss, aand donnt deccodee * wwronng ccmdss: rretuurn ENOOTTYY (iinappp

36、roopriiatee iooctll) bbefoore acccesss_okk() */if (_IOOC_TTYPEE(cmmd) != SCUULL_IOCC_MAAGICC) reeturrn -ENOOTTYY;if (_IOOC_NNR(ccmd) SCUULL_IOCC_MAAXNRR) reeturrn -ENOOTTYY;/* * tthe dirrecttionn iss a bittmassk, andd VEERIFFY_WWRITTE ccatcchess R/W * ttrannsfeers. TTypee iis uuserr-orrienntedd, wwh

37、ille * aacceess_ok is kerrnell-orrienntedd, sso tthe connceppt oof reaad andd * wriite iss reeverrsedd */if (_IOOC_DDIR(cmdd) & _IIOC_REAAD) errr = !aacceess_ok(VERRIFYY_WRRITEE, (voiid _usser *)aarg, _IIOC_SIZZE(ccmd);elsee iff (_IOCC_DIIR(ccmd) & _IOOC_WWRITTE) errr = !aacceess_ok(VERRIFYY_REEAD,

38、(vvoidd _useer *)arrg, _IOOC_SSIZEE(cmmd);if (errr) reeturrn -EFAAULTT;在调用 acccesss_okk 之后后, 驱驱动可安安全地进进行真正正的传输输. 加加上 ccopyy_frrom_useer 和和 coopy_to_useer_ 函数, 程序序员可利利用一组组为被最最多使用用的数据据大小(1, 2, 4, 和 88 字节节)而优优化过的的函数. 这些些函数在在下面列列表中描描述, 它们定定义在 :put_useer(ddatuum, ptrr) _puut_uuserr(daatumm, pptr) 这些宏定定义写

39、 dattum 到用户户空间; 它们们相对快快, 并并且应当当被调用用来代替替 coopy_to_useer 无无论何时时要传送送单个值值时. 这些宏宏已被编编写来允允许传递递任何类类型的指指针到 putt_usser, 只要要它是一一个用户户空间地地址. 传送的的数据大大小依赖赖 prrt 参参数的类类型, 并且在在编译时时使用 sizzeoff 和 typpeoff 等编编译器内内建宏确确定. 结果是是, 如如果 pprt 是一个个 chhar 指针, 传送送一个字字节, 以及对对于 22, 44, 和和 可能能的 88 字节节.put_useer 检检查来确确保这个个进程能能够写入入给定

40、的的内存地地址. 它在成成功时返返回 00, 并并且在错错误时返返回 -EFAAULTT. _puut_uuserr 进行行更少的的检查(它不调调用 aacceess_ok), 但但是仍然然能够失失败如果果被指向向的内存存对用户户是不可可写的. 因此此, _puut_uuserr 应当当只用在在内存区区已经用用 acccesss_ook 检检查过的的时候.作为一个个通用的的规则, 当你你实现一一个 rreadd 方法法时, 调用 _pput_useer 来来节省几几个周期期, 或或者当你你拷贝几几个项时时, 因因此, 在第一一次数据据传送之之前调用用 acccesss_ook 一一次, 如同上

41、上面 iiocttl 所所示.get_useer(llocaal, ptrr) _geet_uuserr(loocall, pptr) 这些宏定定义用来来从用户户空间接接收单个个数据. 它们们象 pput_useer 和和 _putt_usser, 但是是在相反反方向传传递数据据. 获获取的值值存储于于本地变变量 llocaal; 返回值值指出这这个操作作是否成成功. 再次, _gett_usser 应当只只用在已已经使用用 acccesss_ook 校校验过的的地址.如果做一一个尝试试来使用用一个列列出的函函数来传传送一个个不适合合特定大大小的值值, 结结果常常常是一个个来自编编译器的的奇怪

42、消消息, 例如covverssionn too noon-sscallar typpe rrequuestted. 在在这些情情况中, 必须须使用 coppy_tto_uuserr 或者者 coopy_froom_uuserr.6.1.5.兼容性性和受限限操作存取一个个设备由由设备文文件上的的许可权权控制, 并且且驱动正正常地不不涉及到到许可权权的检查查. 但但是, 有些情情形, 在保证证给任何何用户对对设备的的读写许许可的地地方, 一些控控制操作作仍然应应当被拒拒绝. 例如, 不是是所有的的磁带驱驱动器的的用户都都应当能能够设置置它的缺缺省块大大小, 并且一一个已经经被给予予对一个个磁盘设设

43、备读写写权限的的用户应应当仍然然可能被被拒绝来来格式化化它. 在这样样的情况况下, 驱动必必须进行行额外的的检查来来确保用用户能够够进行被被请求的的操作.传统上 uniix 系系统对超超级用户户帐户限限制了特特权操作作. 这这意味着着特权是是一个全全有-或或-全无无的东西西 - 超级级用户可可能任意意做任何何事情, 但是是所有其其他的用用户被高高度限制制了. Linnux 内核提提供了一一个更加加灵活的的系统, 称为为能力. 一个个基于能能力的系系统丢弃弃了全有有-或全全无模式式, 并并且打破破特权操操作为独独立的子子类. 这种方方式, 一个特特殊的用用户(或或者是程程序)可可被授权权来进行行

44、一个特特定的特特权操作作而不必必泄漏进进行其他他的, 无关的的操作的的能力. 内核核在许可可权管理理上排他他地使用用能力, 并且且输出 2 个个系统调调用 ccapgget 和 ccapsset, 来允允许它们们被从用用户空间间管理.全部能力力可在 中找到到. 这这些是对对系统唯唯一可用用的能力力; 对对于驱动动作者或或者系统统管理员员, 不不可能不不修改内内核源码码而来定定义新的的. 设设备驱动动编写者者可能感感兴趣的的这些能能力的一一个子集集, 包包括下面面:CAP_DACC_OVVERRRIDEE 这个能力力来推翻翻在文件件和目录录上的存存取的限限制(数数据存取取控制, 或者者 DAAC

45、).CAP_NETT_ADDMINN 进行网络络管理任任务的能能力, 包括那那些能够够影响网网络接口口的.CAP_SYSS_MOODULLE 加载或去去除内核核模块的的能力.CAP_SYSS_RAAWIOO 进行 raww II/O 操作的的能力. 例子子包括存存取设备备端口或或者直接接和 UUSB 设备通通讯.CAP_SYSS_ADDMINN 一个捕获获-全部部的能力力, 提提供对许许多系统统管理操操作的存存取.CAP_SYSS_TTTY_CCONFFIG 进行 ttty 配置任任务的能能力.在进行一一个特权权操作之之前, 一个设设备驱动动应当检检查调用用进程有有合适的的能力; 不这这样做可

46、可能导致致用户进进程进行行非法的的操作, 对系系统的稳稳定和安安全有坏坏的后果果. 能能力检查查是通过过 caapabble 函数来来进行的的(定义义在 ): intt caapabble(intt caapabbiliity); 在 scculll 例子子驱动中中, 任任何用户户被许可可来查询询 quuanttum 和 qquanntumm 集的的大小. 只有有特权用用户, 但是, 可改改变这些些值, 因为不不适当的的值可能能很坏地地影响系系统性能能. 当当需要时时, iiocttl 的的 scculll 实现现检查用用户的特特权级别别, 如如下: if (! cappablle (CAPP

47、_SYYS_AADMIIN) retturnn -EEPERRM;在这个任任务缺乏乏一个更更加特定定的能力力时, CAPP_SYYS_AADMIIN 被被选择来来做这个个测试.6.1.6.iocctl 命令的的实现iocttl 的的 scculll 实现现只传递递设备的的配置参参数, 并且象象下面这这样容易易:swittch(cmdd)casee SCCULLL_IOOCREESETT: scculll_quuanttum = SSCULLL_QQUANNTUMM; scculll_qsset = SSCULLL_QQSETT; brreakk;casee SCCULLL_IOOCSQQUAN

48、NTUMM: /* SSet: arrg ppoinnts to thee vaaluee */ iff (! caapabble (CAAP_SSYS_ADMMIN) retturnn -EEPERRM; reetvaal = _gett_usser(scuull_quaantuum, (innt _usser *)aarg); brreakk;casee SCCULLL_IOOCTQQUANNTUMM: /* TTelll: aarg is thee vaaluee */ iff (! caapabble (CAAP_SSYS_ADMMIN) retturnn -EEPERRM; sccu

49、lll_quuanttum = aarg; brreakk;casee SCCULLL_IOOCGQQUANNTUMM: /* GGet: arrg iis ppoinnterr too reesullt */ reetvaal = _putt_usser(scuull_quaantuum, (innt _usser *)aarg); brreakk;casee SCCULLL_IOOCQQQUANNTUMM: /* QQuerry: retturnn itt (iitss poosittivee) */ reeturrn ssculll_qquanntumm;casee SCCULLL_IO

50、OCXQQUANNTUMM: /* eeXchhangge: usee arrg aas ppoinnterr */ iff (! caapabble (CAAP_SSYS_ADMMIN) retturnn -EEPERRM; tmmp = scculll_quuanttum; reetvaal = _gett_usser(scuull_quaantuum, (innt _usser *)aarg); iff (rretvval = 0) rettvall = _pput_useer(ttmp, (iint _uuserr *)argg); brreakk;casee SCCULLL_IOOC

51、HQQUANNTUMM: /* ssHifft: likke TTelll + Queery */ iff (! caapabble (CAAP_SSYS_ADMMIN) retturnn -EEPERRM; tmmp = scculll_quuanttum; scculll_quuanttum = aarg; reeturrn ttmp;defaaultt: /* rreduundaant, ass cmmd wwas cheeckeed aagaiinstt MAAXNRR */ reeturrn -ENOOTTYY;retuurn rettvall;sculll 还还包含 6 个个入口项

52、项作用于于 scculll_qsset. 这些些入口项项和给 scuull_quaantuum 的的是一致致的, 并且不不值得展展示出来来.从调用者者的观点点看(即即从用户户空间), 这这 6 种传递递和接收收参数的的方法看看来如下下:int quaantuum;iocttl(ffd,SSCULLL_IIOCSSQUAANTUUM, &quuanttum); /* Sett byy poointter */iocttl(ffd,SSCULLL_IIOCTTQUAANTUUM, quaantuum); /* SSet by vallue */iocttl(ffd,SSCULLL_IIOCGGQU

53、AANTUUM, &quuanttum); /* Gett byy poointter */quanntumm = iocctl(fd,SCUULL_IOCCQQUUANTTUM); /* Gett byy reeturrn vvaluue */iocttl(ffd,SSCULLL_IIOCXXQUAANTUUM, &quuanttum); /* Excchannge by poiinteer */quanntumm = iocctl(fd,SCUULL_IOCCHQUUANTTUM, quuanttum); /* EExchhangge bby vvaluue */当然, 一个正正常的驱驱动

54、不可可能实现现这样一一个调用用模式的的混合体体. 我我们这里里这样做做只是为为了演示示做事情情的不同同方式. 但是是, 正正常地, 数据据交换将将一致地地进行, 通过过指针或或者通过过值, 并且要要避免混混合这 2 种种技术.6.1.7.不用 iocctl 的设备备控制有时控制制设备最最好是通通过写控控制序列列到设备备自身来来实现. 例如如, 这这个技术术用在控控制台驱驱动中, 这里里所谓的的 esscappe 序序列被用用来移动动光标, 改变变缺省的的颜色, 或者者进行其其他的配配置任务务. 这这样实现现设备控控制的好好处是用用户可仅仅仅通过过写数据据控制设设备, 不必使使用(或或者有时时候

55、写)只为配配置设备备而建立立的程序序. 当当设备可可这样来来控制, 发出出命令的的程序甚甚至常常常不需要要运行在在和它要要控制的的设备所所在的同同一个系系统上.例如, settterrm 程程序作用用于控制制台(或或者其他他终端)配置, 通过过打印 esccapee 序列列. 控控制程序序可位于于和被控控制的设设备不同同的一台台计算机机上, 因为一一个简单单的数据据流重定定向可完完成这个个配置工工作. 这是每每次你运运行一个个远程 ttyy 会话话时所发发生的事事情: esccapee 序列列在远端端被打印印但是影影响到本本地的 ttyy; 然然而, 这个技技术不局局限于 ttyys.通过打印

56、印来控制制的缺点点是它给给设备增增加了策策略限制制; 例例如, 它仅仅仅当你确确信在正正常操作作时控制制序列不不会出现现在正被被写入设设备的数数据中. 这对对于 tttyss 只是是部分正正确的. 尽管管一个文文本显示示意味着着只显示示 ASSCIII 字符符, 有有时控制制字符可可潜入正正被写入入的数据据中, 并且可可能, 因此, 影响响控制台台的配置置. 例例如, 这可能能发生在在你显示示一个二二进制文文件到屏屏幕时; 产生生的乱码码可能包包含任何何东西, 并且且最后你你常常在在你的控控制台上上出现错错误的字字体.通过写来来控制是是当然的的使用方方法了, 对于于不用传传送数据据而只是是响应

57、命命令的设设备, 例如遥遥控设备备.例如, 被你们们作者当当中的一一个编写写来好玩玩的驱动动, 移移动一个个 2 轴上的的摄像机机. 在在这个驱驱动里, 这个个设备备是一一对老式式步进电电机, 它们不不能真正正读或写写. 给给一个步步进电机机发送送数据流流的概概念没有有任何意意义. 在这个个情况下下, 驱驱动解释释正被写写入的数数据作为为 ASSCIII 命令令并且转转换这个个请求为为脉冲序序列, 来操纵纵步进电电机. 这个概概念类似似于, 有些, 你发发给猫的的 ATT 命令令来建立立通讯, 主要要的不同同是和猫猫通讯的的串口必必须也传传送真正正的数据据. 直直接设备备控制的的好处是是你可以

58、以使用 catt 来移移动摄像像机, 而不必必写和编编译特殊殊的代码码来发出出 iooctll 调用用.当编写面面向命令令的驱动动, 没没有理由由实现 iocctl 命令. 一个个解释器器中的额额外命令令更容易易实现并并使用.有时, 然而, 你可可能选择择使用其其他的方方法:不不必转变变 wrritee 方法法为一个个解释器器和避免免 iooctll, 你你可能选选择完全全避免写写并且专专门使用用 iooctll 命令令, 而而实现驱驱动为使使用一个个特殊的的命令行行工具来来发送这这些命令令到驱动动. 这这个方法法转移复复杂性从从内核空空间到用用户空间间, 这这里可能能更易处处理, 并且帮帮助

59、保持持驱动小小, 而而拒绝使使用简单单的 ccat 或者 echho 命命令. 但但是, 这个文文件的维维护在后后来有些些少见了了. 实实际上, 所有有的当前前使用的的 liibc 实现(包括 uCllibcc) 仅仅将 -40995 到到 -11 的值值当作错错误码. 不幸幸的是, 能够够返回大大的负数数而不是是小的, 没有有多大用用处.6.2.阻塞 I/OO回顾第 3 章章, 我我们看到到如何实实现 rreadd 和 wriite 方法. 在此此, 但但是, 我们跳跳过了一一个重要要的问题题:一个个驱动当当它无法法立刻满满足请求求应当如如何响应应? 一一个对 reaad 的的调用可可能当没

60、没有数据据时到来来, 而而以后会会期待更更多的数数据. 或者一一个进程程可能试试图写, 但是是你的设设备没有有准备好好接受数数据, 因为你你的输出出缓冲满满了. 调用进进程往往往不关心心这种问问题; 程序员员只希望望调用 reaad 或或 wrritee 并且且使调用用返回, 在必必要的工工作已完完成后. 这样样, 在在这样的的情形中中, 你你的驱动动应当(缺省地地)阻塞塞进程, 使它它进入睡睡眠直到到请求可可继续. 本节展示示如何使使一个进进程睡眠眠并且之之后再次次唤醒它它. 如如常, 但是, 我们们必须首首先解释释几个概概念.6.2.1.睡眠的的介绍对于一个个进程睡眠意味着着什么? 当一一

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论