如何转发/复用 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”(或至少是“可选”表)。我们称他们为t1
和t2
。注意:出于我们的目的,这些表不能定义为const
。
2) 还导出两个 size_t 变量,其中包含两个表的“sizeof
”(假设s1
和s2
:size_t s1 = sizeof(t1)
和size_t s2 = sizeof(t2)
)
3) 在驱动程序初始化之前,确定两个表中最大的一个,并将其指针分配给struct drm_driver
的ioctls
字段。该表将成为您合并的“目标”。当然,struct drm_driver
也必须是非const
。
您还必须相应地调整num_ioctls
字段。
4) 通过复制每个具有非 NULL func
字段的元素来合并目标中的第二个表。要测试的元素数量为sX/sizeof(struct drm_ioctl_descr)
,其中sX 是第二个表的大小(即s1
,如果目标是t2
,s2
,如果目标是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 的主机名转发到目标组?