在驱动程序里, 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() 的宏值。

beyes 2009-09-26 11:23
这几个宏的使用格式为

  • _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函数的cmd宏参数的更多相关文章

  1. Linux内核的ioctl函数学习

    Linux内核的ioctl函数学习 来源:Linux公社  作者:Linux 我这里说的ioctl函数是在驱动程序里的,因为我不知道还有没有别的场合用到了ioctl, 所以就规定了我们讨论的范围.为什 ...

  2. linux2.6内核compat_ioctl函数

    一.内核原型(linux2.6.28-7) long (*compat_ioctl)(struct tty_struct *tty, struct file * file,               ...

  3. ioctl函数详细说明

    本函数影响由fd 参数引用的一个打开的文件. #include<unistd.h> int ioctl( int fd, int request, .../* void *arg */ ) ...

  4. (笔记)Linux下的ioctl()函数详解

    我这里说的ioctl函数是指驱动程序里的,因为我不知道还有没有别的场合用到了它,所以就规定了我们讨论的范围.写这篇文章是因为我前一阵子被ioctl给搞混了,这几天才弄明白它,于是在这里清理一下头脑. ...

  5. linux ioctl()函数

    我这里说的ioctl函数是指驱动程序里的,因为我不知道还有没有别的场合用到了它,所以就规定了我们讨论的范围.写这篇文章是因为我前一阵子被ioctl给搞混了,这几天才弄明白它,于是在这里清理一下头脑. ...

  6. Linux下ioctl函数理解

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

  7. Linux下的ioctl()函数详解

    我这里说的ioctl函数是指驱动程序里的,因为我不知道还有没有别的场合用到了它,所以就规定了我们讨论的范围.写这篇文章是因为我前一阵子被ioctl给搞混了,这几天才弄明白它,于是在这里清理一下头脑. ...

  8. 关于 ioctl 函数

    ioctl函数是用于控制的设备的接口 1.底层: long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long ...

  9. IOCTL函数用法

    http://blog.163.com/he_junwei/blog/static/19793764620152510533753/ http://blog.csdn.net/styyzxjq2009 ...

随机推荐

  1. linux mint使用中的问题解决记录

    软件升级失败 换用命令行 sudo apt update sudo apt list --upgradable sudo apt upgrade sudo apt autoremove Enter p ...

  2. Eova 怎么放在 Docker中,使用阿里云流水线构建Eova!!

    Eova 快速开发框架不做过多解释,使用起来超级爽提高了我们的开发效率. 有要了解的可以去官网看下http://www.eova.cn/ 最近我们想在docker中运行并且使用阿里云的云效工具去构建部 ...

  3. mysql统计指定数据库的各表的条数

    mysql统计指定数据库的各表的条数 SELECT table_schema,table_name,table_rows,CREATE_TIME FROM TABLES WHERE TABLE_SCH ...

  4. javacv获取视频第一帧

    第一种是用ffmpeg工具,不过还得安装客户端软件,于是放弃了,还有一种是javacv开源工具,所以选择第二种: 第一种:ffmpeg工具 需要安装ffmpeg软件,支持windows和linux,视 ...

  5. IMX6Q开发板Linux-QT挂载U盘及TF卡

    本文基于:迅为-iMX6开发板Linux-QT挂载U盘及TF卡 如下图所示,qt 启动之后,在超级终端中使用命令“mknod /dev/sda1 b 8 1”创建 U盘的设备节点,如下图所示. 插入 ...

  6. 三、linux-mysql mysql的多实例

    1.什么是mysql多实例 一个机器开通多个端口,运行多个mysql服务器进程,这些服务进程通过不同的socket监听不同的服务端口提供各自的服务,但它们共用一台mysql安装程序,使用不同的my.c ...

  7. vue2.0学习之动画

    下载animate.css <transition name="v"> <div class="content">需要做动画的内容< ...

  8. Traffic Network in Numazu

    Traffic Network in Numazu 题目描述 Chika is elected mayor of Numazu. She needs to manage the traffic in ...

  9. OSI体系结构(七层)

    OSI体系结构,意为开放式系统互联.国际标准组织(国际标准化组织)制定了OSI模型.这个模型把网络通信的工作分为7层,分别是物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 1至4层被认为 ...

  10. getline的使用

    函数定义: getline(istream &in, string &s) 作用: 在C++中用 string 类型进行终端输入字符串时,解决无法输入带有空格的字符串的问题. 功能: ...