据我所知,ioctl()用于向用户空间应用程序公开“扩展”系统调用接口. ioctl()不是添加数千个特定驱动程序独有的系统调用,而是用于通过单个系统调用提供可扩展的驱动程序特定功能.
这看起来很清楚.但是,我正在尝试编译我的第一个使用ioctl()调用的应用程序,我开始怀疑我的理解.
具体来说,我想进行ioctl()调用以“清理”eMMC设备.看一下/usr/include/linux/mmc/ioctl.h(或者在include / uapi / linux / mmc / ioctl.h的内核源代码中),我可以看到这个结构:
struct mmc_ioc_cmd {
// Most fields omitted
int write_flag;
__u32 opcode;
__u32 arg;
};
从用户空间,我没有任何问题,包括这个标题,并将此结构传递给我的ioctl()调用.
所以这就是我的最终消毒片段:
int sanitize(int fd)
{
struct mmc_ioc_cmd command;
memset(&command,sizeof(command));
command.write_flag = 1;
command.opcode = MMC_SWITCH;
command.arg = EXT_CSD_SANITIZE_START << 16;
return ioctl(fd,MMC_IOC_CMD,&command);
}
我的问题是MMC_SWITCH和EXT_CSD_SANITIZE_START都在内核头文件中定义.具体来说,在我的内核源代码中,它们都可以在include / linux / mmc / mmc.h中找到.
我在互联网上看到的一切都说在构建用户空间项目时不包含来自内核源代码的头文件.如果是这种情况,你如何合理地使用MMC ioctl()?内核公开了传递给ioctl()的结构,但似乎只能通过在内核源代码中隐藏的“隐藏”常量填充它来使用该结构.
我目前的解决方案是将必要的常量从内核头文件复制到我自己的项目中,但这对我来说很脏.
我是否误解了ioctl()的用例?这是设计疏忽吗?
您放入操作码字段的值将直接发送到设备.内核并不关心它是什么,并且无法保证设备支持的操作码,或者它对任何特定操作码的行为方式.因此,像MMC_SWITCH这样的操作码不是API的一部分.
据我所知,你应该从相关的MMC标准中获得操作码.
(这不是将这些符号保留在用户空间API之外的一个很好的理由;复制内核头文件比手动转录标准中的值要容易得多.内核实际上有一个特殊情况,可以通过此ioctl处理EXT_CSD_SANITIZE_START .)