Linux内核之ioctl

来源:互联网 发布:七天网络查分登陆入口w 编辑:程序博客网 时间:2024/06/08 09:23

学习计划:
 1.学习高级I/O
 2.进程间的阻塞

内容:
 1.驱动集中实现ioctl

读者只要把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参数的组织还是比较复杂的,我认为要搞熟他还是得花不少时间的,不过这是值得的,
 驱动程式中最难的是对中断的理解。

/* Direction bits*/
    
#define _IOC_NONE 0U //没有数据传输
     
#define _IOC_WRITE 1U //向设备写入数据,驱动程序必须从用户空间读入数据
      
#define _IOC_READ 2U //从设备中读取数据,驱动程序必须向用户空间写入数据
       
#define _IOC(dir,type,nr,size) \
     
(((dir) << _IOC_DIRSHIFT) | \
      
((type) << _IOC_TYPESHIFT) | \
       
((nr) << _IOC_NRSHIFT) | \
        
((size) << _IOC_SIZESHIFT))

//构造无参数的命令编号
       
#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
        //构造从驱动程序中读取数据的命令编号
         
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))       
        //用于向驱动程序写入数据命令        
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))         
          //用于双向传输         
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
        

0 0