linux驱动ioctl()cmd定义中 _IO, _IOR, _IOW, _IOWR 宏介绍
一、宏介绍
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启动中的使用。
posted on 2018-01-18 19:45 Hello-World3 阅读(1880) 评论(0) 编辑 收藏 举报