如何转发/复用 ioctl 组?

Posted

技术标签:

【中文标题】如何转发/复用 ioctl 组?【英文标题】:How to forward/multiplex group of ioctls? 【发布时间】:2014-01-30 20:10:48 【问题描述】:

我正在尝试在 drm 内核中添加我自己的 ioctls。我已经有了以下内容:

static struct drm_driver my_driver = 
//stuff
.ioctls = my_ioctls,
;

然后我有:

struct drm_ioctl_desc my_ioctls[] = 
// other stuff
DRM_IOCTL_DEF_DRV(MYIOCTL1, myfuncptr, myflags),
DRM_IOCTL_DEF_DRV(MYIOCTL2, myfuncptr2, myflags),
DRM_IOCTL_DEF_DRV(MYIOCTL3, myfuncptr3, myflags),
DRM_IOCTL_DEF_DRV(MYIOCTL4, myfuncptr4, myflags),

但是我将如何多路复用一组 ioctl 并让它们在可能编译或不编译的另一个文件/子文件夹中处理?

即我不想在 my_ioctls 结构中定义额外的 ioctls,因为如果使用某个配置,它们可能会调用未定义的函数。有没有办法在其他地方定义它们并在这种情况下处理它们?

谢谢! (我对此有些陌生,我想我了解基础知识,但我可能会忽略一些东西。)

【问题讨论】:

【参考方案1】:

一种可能的方法(粗鲁,更简洁的解决方案见下文)是通过在调用特定于 drm 的设备分配器之前立即合并两个不同的表来构建一个 ioctl 表(例如drm_dev_alloc)。这两个表来自不同的驱动程序部分,包含不同的服务子集。可选部分可能依赖于编译器宏来创建表的完整版本或“存根”(空)版本。这是一个非常棘手的解决方案,并且肯定容易出错。基本上,鉴于这两个表,你必须

1) 将每个表导出为“extern”(或至少是“可选”表)。我们称他们为t1t2。注意:出于我们的目的,这些表不能定义为const

2) 还导出两个 size_t 变量,其中包含两个表的“sizeof”(假设s1s2size_t s1 = sizeof(t1)size_t s2 = sizeof(t2)

3) 在驱动程序初始化之前,确定两个表中最大的一个,并将其指针分配给struct drm_driverioctls 字段。该表将成为您合并的“目标”。当然,struct drm_driver 也必须是非const。 您还必须相应地调整num_ioctls 字段。

4) 通过复制每个具有非 NULL func 字段的元素来合并目标中的第二个表。要测试的元素数量为sX/sizeof(struct drm_ioctl_descr),其中sX 是第二个表的大小(即s1,如果目标是t2s2,如果目标是t1)。

5) 现在您可以照常注册驱动程序了。

好的,现在是更干净和“标准”的解决方案

在“简化”版本中,将所有可选 ioctl 实现为始终返回 -EINVAL-EOPNOTSUPP 的函数。唯一的缺点是,在您的表中,您始终必须提供所有服务(即使是尚未实施的服务)。

【讨论】:

所以本质上是创建一个新的 ioctl 结构,其大小与所有现有结构和任何新结构相同,然后将该指针传递给 .ioctl?是的,这可能有效,尽管我不确定它是否比仅仅为不存在的代码声明存根函数更干净;)谢谢 是的,正确的。而且,是的,它不是很干净。 (唯一的)优点是您不需要通过声明您最终可能需要的所有可能存根来“预测未来”。 是的,有道理。谢谢 “干净”的方式对用户来说更好,他们可以随心所欲地调用并得到合理的答案。 用户无论如何都可以调用他们想要的任何东西,如果一个函数没有实现(即它的函数指针为空),linux'内核会通过返回一个错误代码(EINVAL,据我记得)正确反应.

以上是关于如何转发/复用 ioctl 组?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Free Pascal 上为接口列表或其他 ioctl 调用 ioctl?

如何调用 compat_ioctl 或 unlocked_ioctl?

生成 ioctl 编号的 asm/ioctl.h 宏的强制性程度如何?

如何让 AWS ELB 将实际主机名而不是 ELB 的主机名转发到目标组?

如何正确地将 C ioctl 调用转换为 python fcntl.ioctl 调用?

如何修复 ioctl 请求阻止设备的“无效参数”