Skip to main content
 首页 » 操作系统

linux驱动ioctl()cmd定义中 _IO, _IOR, _IOW, _IOWR 宏介绍

2022年07月19日26daizhj

一、宏介绍

1. 在驱动中 ioctl() 参数 cmd 是应用发给驱动的命令代码,cmd 除了可区别的普通数字外,还可以使用包含有助于处理的几种相应信息的数字作为cmd,cmd为int型,32位,共分 4 个域:

bit31~bit30 2位为 "区别读写" 区,作用是区分是读取命令还是写入命令。
bit29~bit15 14位为 "数据大小" 区,表示 ioctl() 中的 arg 变量传送的内存大小。
bit20~bit08 8位为 "魔数"(也称为"幻数")区,这个值用以与其它设备驱动程序的 ioctl 命令进行区别。
bit07~bit00 8位为 "区别序号" 区,是区分命令的命令顺序序号。

2. 宏定义为:

#define _IOC(dir, type, nr, size) ((dir  << 30) |(type << 8) | (nr   << 0) | (size << 16))

其它宏都是由此宏衍生出来的:

///include/uapi/asm-generic/ioctl.h 
#define _IO(type, nr)              _IOC(0, type, nr ,0) 
#define _IOR(type, nr, size)       _IOC(2, type, nr, sizeof(size)) //有对参数大小的check,注意宏中的size是参数的类型 
#define _IOW(type, nr, size)       _IOC(1, type, nr, sizeof(size)) //有对参数大小的check 
#define _IOWR(type, nr, size)      _IOC(3, type, nr, sizeof(size)) //有对参数大小的check 
#define _IOR_BAD(type, nr, size)   _IOC(2, type, nr, sizeof(size)) //没有对参数大小的check 
#define _IOW_BAD(type, nr, size)   _IOC(1, type, nr, sizeof(size)) //有对参数大小的check 
#define _IOWR_BAD(type, nr, size)  _IOC(3, type, nr, sizeof(size)) //有对参数大小的check

下面还定义了一些帮助宏:

///include/uapi/asm-generic/ioctl.h 
#define _IOC_DIR(nr)    (nr >> 30) & (1<<2 -1) 
#define _IOC_TYPE(nr)   (nr >> 8) & (1<<8 -1) 
#define _IOC_NR(nr)     (nr >> 0) & (1<<8 -1) 
#define _IOC_SIZE(nr)   (nr >> 16) & (1<<14 -1) 
 
#define IOC_IN         1 << 30 
#define IOC_OUT        2 << 30 
#define IOC_INOUT      3 << 30 
#define IOCSIZE_MASK  (1<<14 - 1) << 16 
#define IOCSIZE_SHIFT 16

注:为了阅读方便,这里把出于使用安全考虑的括号给去掉了。比如 _IOC_NR(CMD1) 就可以知道CMD1这个命令是哪个命令了,_IOC_NR(CMD_LAST) 就可以知道一共有多少个命令了。

二、说明

1. 使用 _IO、_IOR、_IOW、_IOWR 定义的cmd命令,只要nr不重复,就不会出现重复的命令。

2. 驱动可以使用这些宏,也可以不使用,可理解为这个是属于驱动自己定义的协议自己遵守。

3. 使用这些宏可以增加代码的可读性,当当看到驱动自己定义的cmd命令宏的时候,就可以知道是读还是写,以及cmd跟的arg参数的大小。

4. 对于负载的驱动,建议使用,比如Android中的binder驱动,ioctl()的二级cmd(BC_XXX/BR_XXX)是和数据都放在buffer中的,使用这些宏后,读取到命令后,就可以知道接下来的args要读取多少字节。

三、举例

enum ctrl_cmd_id { 
    SET_FPS = 1, 
    GET_FPS, 
    ... 
    CMD_ID_MAX 
}; 
 
//SET_FPS 命令的参数结构 
struct ctrl_data { 
    pid_t pid; 
    int level; 
}; 
 
#define DEMO_MAGIC 0xee 
#define CMD_ID_SET_FPS \ 
    _IOWR(DEMO_MAGIC, SET_FPS, struct ctrl_data) 
#define CMD_ID_GET_FPS \ 
    _IOWR(DEMO_MAGIC, GET_FPS, unsigned int) 
... 
 
 
static long demo_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 
{ 
    void __user *uarg = (void __user *)arg; 
 
    /* 通过这两个成员来判断cmd是否合法 */ 
    if (_IOC_TYPE(cmd) != DEMO_MAGIC) 
        return -EINVAL; 
 
    if (_IOC_NR(cmd) >= CMD_ID_MAX) 
        return -EINVAL; 
 
    ... 
}

四、补充

1. 可参考binder启动中的使用。


本文参考链接:https://www.cnblogs.com/hellokitty2/p/8312736.html