对ioctl()和内核头文件的困惑

时间:2016-11-22 22:43:40

标签: c linux linux-kernel linux-device-driver ioctl

据我所知,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, 0, 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_SWITCHEXT_CSD_SANITIZE_START都在内核头文件中定义。具体来说,在我的内核源代码中,他们都在include/linux/mmc/mmc.h找到了。

我在互联网上看到的所有内容都表示在构建用户空间项目时包含来自内核源代码的标头。如果是这种情况,您如何合理地使用MMC ioctl()?内核公开了传递给ioctl()的结构,但似乎只能通过填充&#34;隐藏&#34;来使用该结构。隐藏在内核源代码中的常量。

我目前的解决方案是将必要的常量从内核头文件复制到我自己的项目中,但这对我来说很脏。

我是否误解了ioctl()的用例?这是设计疏忽吗?

2 个答案:

答案 0 :(得分:2)

MMC_IOC_CMD ioctl和相应的mmc_ioc_cmd结构是Linux用户空间API的一部分,因此在安装到uapi的{​​{1}}标头中定义

您放入/usr/include字段的值会直接发送到设备。内核并不关心它是什么,并且无法保证设备支持的操作码,或者它对任何特定操作码的行为方式。因此,像opcode这样的操作码不是 API的一部分。

据我所知,您应该从相关的MMC标准中获取操作码。

(这不是将这些符号保留在用户空间API之外的一个很好的理由;复制内核头文件比手动转录标准中的值要容易得多。内核实际上有一个处理{的特殊情况{1}}通过这个ioctl。)

答案 1 :(得分:1)

如果您{G}命令行上没有添加任何其他#include包含路径-I,那么您就可以了。

  

我在互联网上看到的所有内容都表示在构建用户空间项目时包含来自内核源代码的标头。

该建议意味着不直接在内核源代码树中包含标头。 uapi标头旨在从用户空间使用,并安装到/usr/include