在和设备驱动程序通信时,ioctl是很常用的一个调用,常用来配置、查询或者修改设备的配置。反过来说,编写驱动程序时,ioctl也是经常要实现的一个接口,以便应用程序可以方便地控制设备驱动。
应用程序中的ioctl
ioctl函数的原型如下:
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
可以看出该函数是一个可变参数的函数。第一个参数是一个文件描述符,通常用open调用来打开。在Linux中,一切皆文件,哪怕你调用open打开一个设备,也得到一个文件描述符。这一切要归功于内核里的VFS(虚拟文件系统)。第二个参数request是控制代码,或者说是控制命令、请求代码都可以。根据第二个参数的不同,后面所带的参数个数和类型都可能不一样。
内核中的ioctl
当引用进程调用ioctl时,Linux内核中实现的系统调用被调用。系统调用是Linux的一种标准机制,在不同的CPU体系结构中的具体实现方式可能不一样。ioctl系统调用定义于内核源码的fs/ioctl.c中,其定义如下:
SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
{
struct fd f = fdget(fd);
int error;
if (!f.file)
return -EBADF;
error = security_file_ioctl(f.file, cmd, arg);
if (error)
goto out;
error = do_vfs_ioctl(f.file, fd, cmd, arg);
if (error == -ENOIOCTLCMD)
error = vfs_ioctl(f.file, cmd, arg);
out:
fdput(f);
return error;
}
从ioctl系统调用的源码可以看出,它首先会调用do_vfs_ioctl,如果do_vfs_ioctl不支持这个控制命令,则调用vfs_ioctl。
do_vfs_ioctl函数的源码可点击链接直接查看,它主要处理一些文件系统通用的控制命令,如FIOASYNC等,详细控制命令列表可查看该函数源码。另外,该函数还会判断文件节点是不是常规文件,如果是则调用file_ioctl函数。后者也处理一些跟文件相关的控制命令。
对于设备驱动的控制命令,一般