linux系统下的ioctl函数

来源:互联网 发布:python help 退出 编辑:程序博客网 时间:2024/04/28 22:49

我这里说的ioctl函数是在驱动程式里的,因为我不知道更有没有别的场合用到了ioctl,
      所以就规定了我们讨论的范围。为什么要写篇文章呢,是因为我前一阵子被ioctl给搞混
      了,这几天才弄明白他,于是在这里清理一下头脑。
      
      一、 什么是ioctl。
      ioctl是设备驱动程式中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就
      是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。他的调用个数
      如下:
      int ioctl(int fd, ind cmd, …);
      其中fd就是用户程式打开设备时使用open函数返回的文件标示符,cmd就是用户程式对设
      备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,有或没有是和
      cmd的意义相关的。
      ioctl函数是文件结构中的一个属性分量,就是说如果你的驱动程式提供了对ioctl的支
      持,用户就能在用户程式中使用ioctl函数控制设备的I/O通道。
      
      二、 ioctl的必要性
      如果不用ioctl的话,也能实现对设备I/O通道的控制,但那就是蛮拧了。例如,我们可
      以在驱动程式中实现write的时候检查一下是否有特别约定的数据流通过,如果有的话,
      那么后面就跟着控制命令(一般在socket编程中常常这样做)。不过如果这样做的话,会
      导致代码分工不明,程式结构混乱,程式员自己也会头昏眼花的。
      所以,我们就使用ioctl来实现控制的功能。要记住,用户程式所作的只是通过命令码告
      诉驱动程式他想做什么,至于怎么解释这些命令和怎么实现这些命令,这都是驱动程式要
      做的事情。
      
      三、 ioctl怎么实现
      这是个非常麻烦的问题,我是能省则省。要说清晰他,没有四五千字是不行的,所以我这
      里是不可能把他说得非常清晰了,不过如果有读者对用户程式怎么和驱动程式联系起来感
      兴趣的话,能看我前一阵子写的《write的奥秘》。读者只要把write换成ioctl,就知
      道用户程式的ioctl是怎么和驱动程式中的ioctl实现联系在一起的了。
      我这里说一个大概思路,因为我觉得《Linux设备驱动程式》这本书已说的非常清晰
      了,不过得化一些时间来看。
      在驱动程式中实现的ioctl函数体内,实际上是有一个switch{case}结构,每一个case对
      应一个命令码,做出一些相应的操作。怎么实现这些操作,这是每一个程式员自己的事
      情,因为设备都是特定的,这里也没法说。关键在于怎么样组织命令码,因为在ioctl中
      命令码是唯一联系用户程式命令和驱动程式支持的途径。
      命令码的组织是有一些讲究的,因为我们一定要做到命令和设备是一一对应的,这样才不
      会将正确的命令发给错误的设备,或是把错误的命令发给正确的设备,或是把错误的
      命令发给错误的设备。这些错误都会导致不可预料的事情发生,而当程式员发现了这些奇
      怪的事情的时候,再来调试程式查找错误,那将是非常困难的事情。
      所以在Linux核心中是这样定义一个命令码的:
      ____________________________________
      | 设备类型 | 序列号 | 方向 |数据尺寸|
      |----------|--------|------|--------|
      | 8 bit    |  8 bit |2 bit |8~14 bit|
      |----------|--------|------|--------|

      这样一来,一个命令就变成了一个整数形式的命令码。不过命令码非常的不直观,所以
      Linux Kernel中提供了一些宏,这些宏可根据便于理解的字符串生成命令码,或是从
      命令码得到一些用户能理解的字符串以标明这个命令对应的设备类型、设备序列号、数
      据传送方向和数据传输尺寸。
      
      这些宏我就不在这里解释了,具体的形式请读者察看Linux核心原始码中的和,文件里给
      除了这些宏完整的定义。这里我只多说一个地方,那就是"幻数"。
      幻数是个字母,数据长度也是8,所以就用一个特定的字母来标明设备类型,这和用一
      个数字是相同的,只是更加利于记忆和理解。就是这样,再没有更复杂的了。
      更多的说了也没有,读者还是看一看原始码吧,推荐各位阅读《Linux 设备驱动程式》所
      带原始码中的short一例,因为他比较短小,功能比较简单,能看明白ioctl的功能和细
      节。

      四、 cmd参数怎么得出
      这里确实要说一说,cmd参数在用户程式端由一些宏根据设备类型、序列号、传送方向、
      数据尺寸等生成,这个整数通过系统调用传递到内核中的驱动程式,再由驱动程式使用解
      码宏从这个整数中得到设备的类型、序列号、传送方向、数据尺寸等信息,然后通过
      switch{case}结构进行相应的操作。
      要透彻理解,只能是通过阅读原始码,我这篇文章实际上只是个引子。Cmd参数的组织
      还是比较复杂的,我认为要搞熟他还是得花不少时间的,不过这是值得的,驱动程式中最
      难的是对中断的理解。

      五、 小结
      ioctl其实没有什么非常难的东西需要理解,关键是理解cmd命令码是怎么在用户程式里生成
      并在驱动程式里解析的,程式员最主要的工作量在switch{case}结构中,因为对设备的
      I/O控制都是通过这一部分的代码实现的。

      参考资料:
      1.《Linux 设备驱动程式》,鲁宾尼著,中国电力出版社。

原创粉丝点击