一、定义
ioctl 是设备驱动程序中设备控制接口函数,一个字符设备驱动通常会实现设备打开、关闭、读、写等功能,在一些需要细分的情境下,如果需要扩展新的功能,通常以增设 ioctl() 命令的方式实现。
简言之就是对设备的一些特性进行管理,例如传感器的数据采集频率、串口波特率、停止位等等。
- 通常来说,使用read write接口,来读写数据;使用ioctl接口设置一些属性等等。
- ioctl接口既可以读,也可以写,但是读写大数据的效率不如使用read write接口高。
需要注意的是:新内核中file_operations 结构体对ioctl接口的定义发生了变化, :
原先的, 参见include/linux/fs.h, version 2.6.17, line 1015
int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long);
被改为了, 参见include/linux/fs.h, version 4.11, line 1654,
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
ref:
二、命令格式
在linux中,提供了一种 ioctl 命令的统一格式,将 32 位 int 型数据划分为四个位段,如下图所示:
内核的 /include/uapi/asm-generic/ioctl.h
头文件,定义了 ioctl 函数的相关宏
/* 合成宏 */
#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
#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)))
/*
_IO: 定义没有数据传递的 ioctl 命令
_IOW: 定义向驱动中写入数据的 ioctl 命令(copy_from_user)
_IOR: 定义从驱动中读数据的ioctl命令(copy_to_user)
_IOWR: 定义带读写参数的 ioctl 命令,先写后读的这类命令
*/
/* 反向解析 ioctl 宏接口 */
#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
三、代码示例
和open read write函数同理,当在应用层代码中调用ioctl接口的时候,其实调用的内核file_operations的unlocked_ioctl结构体成员。
用户空间:
#include <sys/ioctl.h>
int ioctl(int fd, int cmd, ...) ;
输入参数:
- 参数1:设备描述符
- 参数2:指令,如某一个命令对应驱动层的某一个功能
- 参数3:可变参数,跟命令有关,传递进入驱动层的参数或者是接收数据的缓存
返回值:
- 成功:返回 0
- 失败:返回 -1,并设置全局变量 errorno 值
代码示例:
/* 定义命令 */
#define MYCMD _IO('c', 0)
int ret;
ret = ioctl(fd, MYCMD);
if (ret == -1) {
printf("ioctl: %s\n", strerror(errno));
}
内核空间:
#include <linux/ioctl.h> /* 内核空间 */
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
- 参数1:文件结构体指针
- 参数2:指令(对应应用层ioctl函数的第二个参数)
- 参数3:应用层传递给驱动层的数据或者是接收数据用到的缓存地址
ref: