ioctl() 参数

摘要:
在驱动程序中,ioctl()函数上传输的变量cmd是应用程序用来区分设备驱动程序请求的处理内容的值。除了区分数字之外,cmd还包含一些有助于处理的相应信息。cmd的大小为32位,分为四个域:bit31~bit302位是“区分读/写”区域,用于区分读命令和写命令。Bit29~bit1514位是“数据大小”区域,表示ioctl()中arg变量传输的内存大小。

在驱动程序里, ioctl() 函数上传送的变量 cmd 是应用程序用于区别设备驱动程序请求处理内容的值。cmd除了可区别数字外,还包含有助于处理的几种相应信息。 cmd的大小为 32位,共分 4 个域:
     bit31~bit30 2位为 “区别读写” 区,作用是区分是读取命令还是写入命令。
     bit29~bit15 14位为 "数据大小" 区,表示 ioctl() 中的 arg 变量传送的内存大小。
     bit20~bit08  8位为 “魔数"(也称为"幻数")区,这个值用以与其它设备驱动程序的 ioctl 命令进行区别。
     bit07~bit00   8位为 "区别序号" 区,是区分命令的命令顺序序号。
像 命令码中的 “区分读写区” 里的值可能是 _IOC_NONE (0值)表示无数据传输,_IOC_READ (读), _IOC_WRITE (写) , _IOC_READ|_IOC_WRITE (双向)。
内核定义了 _IO() , _IOR() , IOW() 和 _IOWR() 这 4 个宏来辅助生成上面的 cmd 。下面分析 _IO() 的实现,其它的类似:

在 asm-generic/ioctl.h 里可以看到 _IO() 的定义

      #define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)

再看 _IOC() 的定义

     #define _IOC(dir,type,nr,size) \
                   (((dir)  << _IOC_DIRSHIFT) | \
                   ((type) << _IOC_TYPESHIFT) | \
                   ((nr)   << _IOC_NRSHIFT) | \
                   ((size) << _IOC_SIZESHIFT))

可见,_IO() 的最后结果由 _IOC() 中的 4 个参数移位组合而成。
再看 _IOC_DIRSHIT 的定义

            #define _IOC_DIRSHIFT    (_IOC_SIZESHIFT+_IOC_SIZEBITS)

      _IOC_SIZESHIFT 的定义

           #define _IOC_SIZESHIFT    (_IOC_TYPESHIFT+_IOC_TYPEBITS)

      _IOC_TYPESHIF 的定义

           #define _IOC_TYPESHIFT    (_IOC_NRSHIFT+_IOC_NRBITS)

      _IOC_NRSHIFT 的定义

           #define _IOC_NRSHIFT    0

      _IOC_NRBITS 的定义

          #define _IOC_NRBITS    8

      _IOC_TYPEBITS 的定义

         #define _IOC_TYPEBITS    8

由上面的定义,往上推得到

      引 用

       _IOC_TYPESHIFT = 8

       _IOC_SIZESHIFT = 16

       _IOC_DIRSHIFT = 30

所以,(dir)  << _IOC_DIRSHIFT) 表是 dir 往左移 30 位,即移到 bit31~bit30 两位上,得到方向(读写)的属性;
       (size) << _IOC_SIZESHIFT) 位左移 16 位得到“数据大小”区;
       (type) << _IOC_TYPESHIFT) 左 移 8位得到"魔数区" ;
       (nr)   << _IOC_NRSHIFT)      左移 0 位( bit7~bit0) 。
这样,就得到了 _IO() 的宏值。

这几个宏的使用格式为

  • _IO (魔数, 基数);
  • _IOR (魔数, 基数, 变量型)
  • _IOW  (魔数, 基数, 变量型)
  • _IOWR (魔数, 基数,变量型 )

魔数 (magic number)
      魔数范围为 0~255 。通常,用英文字符"A" ~ "Z" 或者 "a" ~ "z"来表示。设备驱动程序从传递进来的命令获取魔数,然后与自身处理的魔数想比较,如果相同则处理,不同则不处理。魔数是拒绝误使用的初步辅助状态。设备驱动程序可以通过 _IOC_TYPE (cmd)来获取魔数。不同的设备驱动程序最好设置不同的魔数,但并不是要求绝对,也是可以使用其他设备驱动程序已用过的魔数。
基(序列号)数
     基数用于区别各种命令。通常,从0开始递增,相同设备驱动程序上可以重复使用该值。例如,读取和写入命令中使用了相同的基数,设备驱动程序也能分辨出来,原因在于设备驱动程序区分命令时使用 switch ,且直接使用命令变量cmd值。创建命令的宏生成的值由多个域组合而成,所以即使是相同的基数,也会判断为不同的命令。设备驱动程序想要从命令中获取该基数,就使用下面的宏:
_IOC_NR (cmd)
通常,switch 中的 case 值使用的是命令的本身。
变量型
      变量型使用 arg 变量指定传送的数据大小,但是不直接代入输入,而是代入变量或者是变量的类型,原因是在使用宏创建命令,已经包含了 sizeof() 编译命令。比如 _IOR() 宏的定义是:

      引用

      #define _IOR(type,nr,size)    _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))

而 _IOC_TYPECHECK() 的定义正是:

      引用

      #define _IOC_TYPECHECK(t) (sizeof(t))

设备驱动程序想要从传送的命令获取相应的值,就要使用下列宏函数:
      _IOC_SIZE(cmd)

_IO 宏

      该宏函数没有可传送的变量,只是用于传送命令。例如如下约定:

      引用

      #define TEST_DRV_RESET _IO ('Q', 0)

此时,省略由应用程序传送的 arg 变量或者代入 0 。在应用程序中使用该宏时,比如:

      ioctl (dev, TEST_DEV_RESET, 0)   或者  ioctl (dev, TEST_DRV_RESET) 。
这是因为变量的有效因素是可变因素。只作为命令使用时,没有必要判 断出设备上数据的输出或输入。因此,设备驱动程序没有必要执行设备文件大开选项的相关处理。

_IOR 宏
     该函数用 于创建从设备读取数据的命令,例如可如下约定:

     引用

     #define TEST_DEV_READ  _IRQ('Q', 1, int)

这说明应用程序从设备读取数据的大小为 int 。下面宏用于判断传送到设备驱动程序的 cmd 命令的读写状态:
     _IOC_DIR (cmd)
运行该宏时,返回值的类型 如下:

  • _IOC_NONE                             :  无属性
  • _IOC_READ                             :  可读属性
  • _IOC_WRITE                           : 可写属性
  • _IOC_READ | _IOC_WRITE : 可读,可写属性

使用该命令时,应用程序的 ioctl() 的 arg 变量值指定设备驱动程序上读取数据时的缓存(结构体)地址。
_IOW 宏
      用于创建设 备上写入数据的命令,其余内容与 _IOR 相同。通常,使用该命令时,ioctl() 的 arg 变量值指定设备驱动程序上写入数据时的缓存(结构体)地址。
_IOWR 宏
      用于创建设备上读写数据的命令。其余内 容与 _IOR 相同。通常,使用该命令时,ioctl() 的 arg 变量值指定设备驱动程序上写入或读取数据时的缓存 (结构体) 地址。
_IOR() , _IOW(), IORW() 的定义
      #define _IOR(type,nr,size)    _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
      #define _IOW(type,nr,size)    _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
      #define _IOWR(type,nr,size)    _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))


免责声明:文章转载自《ioctl() 参数》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇[爬虫]采用Go语言爬取天猫商品页面postman集合(变量及集合执行)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

CMake高级用法

0. 写在最前面本文将总结自己日常用到的CMake命令以及功能。如有错误,欢迎在评论中指正。 如果觉得写得还不错,就请收藏一下啦~~~也可以找一下我写的其他文章来看一下。关注一下我的专栏什么的。 你的Star是作者坚持下去的最大动力哦~~~ 在这里可以查到关于命令的官方文档 使用宏定义:macro macro(add_example name) a...

switch语句不能使用枚举的成员变量

出现问题: 写了个代码,需要使用枚举的来判断对于的事务处理 然而这里的编译器报错:constant expression required switch 的case中,必须要用常量,想了一下,枚举里面的code是可以相同的 实在不想在 类里面 定义 public static final int code 这样的常量来代替枚举 解决方法: 在枚举类中添加...

边界值法设计测试用例

大量的测试实践表明,很多错误是发生在输入或输出数据范围的边界上,因此针对各种边界情况设计测试用例,有利于揭露程序中的错误。 边界值分析法是对等价类分析法的补充。边界值分析法利用各输入等价类的最小值、略大于最小值的值、正常值、略小于最大值的值和最大值处进行取值。 1.“单故障”假设 边界值分析的另外一个要点基于一个十分重要的假设“单故障”假设,即失效问题通常...

单片机沉思录——再谈static

静态变量作用范围在一个文件内,程序开始时分配空间,结束时释放空间,默认初始化为0,使用时可以改变其值。     静态变量或静态函数只有本文件内的代码才能访问它,它的名字在其它文件中不可见。用法1:函数内部声明的static变量,可作为对象间的一种通信机制     如果一局部变量被声明为static,那么将只有唯一的一个静态分配的对象,它被用于在该函数的所...

ORACLE 存储过程提高

1.SQLCODE和SQLERRM 2.%TYPE和%ROWTYPE的使用 3.sql%rowcount的作用 1.SQLCODE和SQLERRM  SQLCode:数据库操作的返回码,其中 0--成功; -1--失败; 100--没有检索到数据。 +1--用户自定义异常 sqlerrm函数返回指定错误代码的错误信息。  在一个内在的异常中,SQLC...

Shell 编程

  Shell 是一门脚本语言(又称解释型语言),Shell 其实就是一个纯文本文件,通常以【#!/bin/bash】开始。脚本自上而下,从左至右分析并执行,其中【#】后面的为注释。脚本有以下几种运行方式:(1) 【bash shell.sh】 (2)【sh shell.sh】(3)【./shell.sh】当前目录下执行,用户必须有可执行权限 (4)【. ....