一、 什么是ioctl

ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。它的调用个数如下:

  int ioctl(int fd, ind cmd, …);

其中fd就是用户程序打开设备时使用open函数返回的文件标示符,cmd就是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,有或没有是和cmd的意义相关的,如果有的话,第三个参数总是一个指针,但指针的类型依赖于request参数。

ioctl函数是文件结构中的一个属性分量,就是说如果你的驱动程序提供了对ioctl的支持,用户就可以在用户程序中使用ioctl函数控制设备的I/O通道。

二、 ioctl的必要性 
如果不用ioctl的话,也可以实现对设备I/O通道的控制,但那是蛮拧了。例如,我们可以在驱动程序中实现write的时候检查一下是否有特殊约定的数 据流通过,如果有的话,那么后面就跟着控制命令(一般在socket编程中常常这样做)。但是如果这样做的话,会导致代码分工不明,程序结构混乱,程序员 自己也会头昏眼花的。所以,我们就使用ioctl来实现控制的功能。要记住,用户程序所作的只是通过命令码(cmd)告诉驱动程序它想做什么,至于怎么解释这些命令和怎么实现这些命令,这都是驱动程序要做的事情。

三、 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控制都是通过这一部分的代码实现的。

Linux下ioctl函数理解的更多相关文章

  1. 对于linux下system()函数的深度理解(整理)

    原谅: http://blog.sina.com.cn/s/blog_8043547601017qk0.html 这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同 ...

  2. 转:对于linux下system()函数的深度理解(整理)

    这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system()函数中调用的命令也都一切正常.就没理这个bug,以为 ...

  3. (笔记)Linux下system()函数的深度理解(整理)

    注:从其它地方转的非常好的一篇文章,值得深究! 这几天调程序(嵌入式linux),发现程序有时就莫名其妙的死掉,每次都定位在程序中不同的system()函数,直接在shell下输入system()函数 ...

  4. [转帖]Linux下fork函数及pthread函数的总结

    Linux下fork函数及pthread函数的总结 https://blog.csdn.net/wangdd_199326/article/details/76180514 fork Linux多进程 ...

  5. linux select函数:Linux下select函数的使用详解【转】

    本文转载自;http://www.bkjia.com/article/28216.html Linux下select函数的使用 Linux下select函数的使用 一.Select 函数详细介绍 Se ...

  6. linux下syscall函数,SYS_gettid,SYS_tgkill

    出处:http://blog.chinaunix.net/uid-28458801-id-4630215.html     linux下syscall函数,SYS_gettid,SYS_tgkill  ...

  7. Linux下c函数dlopen实现加载动态库so文件代码举例

    dlopen()是一个强大的库函数.该函数将打开一个新库,并把它装入内存.该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的.这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了. ...

  8. 【C/C++】Linux下system()函数引发的错误

    http://my.oschina.net/renhc/blog/54582 [C/C++]Linux下system()函数引发的错误 恋恋美食  恋恋美食 发布时间: 2012/04/21 11:3 ...

  9. linux下sprintf_s函数的替代

    error code: ]; sprintf_s(buf, , "predicted position:(%3d, %3d)", predict_pt.x, predict_pt. ...

随机推荐

  1. SQL 索引查找

    索引查找信息 在非聚集索引里,会为每条记录存储一份非聚集索引索引键的值和一份聚集索引索引键 [在没有聚集索引的表格里,是RID值指向数据页面,有聚集索引的话指向聚集索引的键(在不使用include时) ...

  2. More than one fragment with the name [spring_web] was found. This is not legal ...

    今天在搭建springweb应用环境的时候启动tomcat报错More than one fragment with the name [spring_web] was found. This is ...

  3. java编程基础二进制

    0.java编程基础 01.二进制(原码,反码,补码) 02.位运算 03.移位运算符 二进制 原码,反码,补码 1.基本概念 二进制是逢2进位的进位制,0,1是基本算符. 现在的电子计算机技术全部使 ...

  4. Kendo MVVM 数据绑定(八) Style

    Kendo MVVM 数据绑定(八) Style Style 绑定可以通过 ViewModel 绑定到 DOM 元素 CSS 风格属性,例如: <span data-bind="sty ...

  5. Android方法数methods超过65536

    当Android App中的方法数超过65535时,如果往下兼容到低版本设备时,就会报编译错误: Cannot fit requested classes in a single dex file. ...

  6. centos 安装 rtmp nginx 视频流服务器

    ---恢复内容开始--- 1.使用yum安装git yum -y install git 2.下载nginx-rtmp-module,官方github地址 // 通过git clone 的方式下载到服 ...

  7. SDUT 1309 不老的传说问题 (区间DP)

    题意: 有一个环形序列,n个数字表示一种颜色,要求将白板环刷成一模一样的环,限制是每次最多只能刷连续的K个位置,问最少需要刷几次? 思路: 跟2008长春那道painter string 差不多.只是 ...

  8. RYU的GUI安装

    1. RYU安装 Ubuntu14.04 LTS 1.sudo apt-get install git python-pip libxml2-dev libxslt1-dev python2.7-de ...

  9. 如何对ABAP SE80 workbench做增强

    流程如下: 要获取更多Jerry的原创文章,请关注公众号"汪子熙":

  10. python+opencv模拟生成运动模糊核

    Mark:https://www.cnblogs.com/wyh1993/p/7118559.html 效果非常的好