两个相互依赖的Linux内核模块的结构?
在我参与的一个项目中,我们有以下硬件设置:
Linux PC ------> "Router" +----> "Device A" | +----> "Device B"
Linux PC 是标准 X86 PC。
“路由器”是我们开发的一个硬件,它连接到我们系统中的其他硬件。在此示例中为“设备 A”。 “路由器”通过 USB 连接到 Linux PC。
“设备 A” 和“设备 B” 是系统中的硬件。它们通过某种通信通道连接到“路由器”硬件(在这种情况下不重要)。
我的任务是为“设备 A”(以及后来的其他设备)编写 Linux 设备驱动程序。
我已经构建了一个与“路由器”对话的通用 USB 驱动程序,并且效果很好。我的计划是拥有一个如下所示的驱动程序堆栈:
+----------+----------+ | dev_A.ko | dev_B.ko | +----------+----------+ | router.ko | +---------------------+ | Linux USB driver | +---------------------+
即:设备驱动程序使用“router.ko”内核模块与其硬件进行通信,而该模块又构建在标准 Linux USB 驱动程序核心上。
我的问题是,对于 Linux PC,只有一个物理设备:通过 USB 连接的“路由器”硬件,这意味着设备驱动程序成为某种虚拟设备。
我可以将设备驱动程序和路由器设备驱动程序编译成一个大内核模块,但这似乎不是最好的解决方案。
此外,由于“设备 A”之前已直接连接到 Linux PC,因此已经存在一个具有明确定义的用户空间接口的驱动程序,必须保留该驱动程序,因为生产中已经有应用程序需要与其通信。
我的问题或多或少可以归结为:
鉴于上述硬件场景,您将如何构建 Linux 内核模块?
In a project I am involved in we have the following hardware setup:
Linux PC ------> "Router" +----> "Device A" | +----> "Device B"
Linux PC is a standard X86 PC.
"Router" is a piece of hardware we developed that is connected to other pieces of hardware in our system. In this example "Device A". The "Router" is connected to the Linux PC using USB.
"Device A" and "Device B" are pieces of hardware in the system. They are connected to the "Router" hardware via some communication channel (unimportant in this case).
My task is to write a Linux device driver for "Device A" (and later other devices as well).
I have already constructed a general purpose USB driver that talks to "Router" and this works fine. My plan was to have a driver stack that would look like this:
+----------+----------+ | dev_A.ko | dev_B.ko | +----------+----------+ | router.ko | +---------------------+ | Linux USB driver | +---------------------+
That is: The device drivers communicate with their hardware using the "router.ko" kernel module which in turn is built on the standard Linux USB driver core.
My problem is that to the Linux PC, there is only one physical device: The "Router" hardware connected via USB, which means the device drivers become some sort of virtual devices.
I could compile teh device drivers and the Router device driver into one big kernel module, but it does not seem like the best solution.
Also, since "Device A" has previously been connected directly to a Linux PC there already exists a driver for it with a well defined userspace-interface which must be kept since there are already applications in production that need to speak to it.
My question more or less boils down to this:
Given the hardware scenario above, how would you structure the Linux kernel modules?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为您提出的解决方案没有任何问题,即使用一个与实际硬件通信的 router.ko 模块以及与 router.ko 通信的子模块 dev_A.ko 和 dev_B.ko 。您只需要让 router.ko 导出一个“my_register_driver”函数,类似于现有的 pci_register_driver 函数。您将传入一个具有“id”成员和“add_device”函数指针的结构; dev_A.ko 将传入 id="A" 和 add_device=dev_A_add,对于 dev_B.ko 也是如此。
然后,当 router.ko 出现时,它会发现硬件并为 A 和 B 创建虚拟设备(您自己的上下文结构)。然后,当子模块出现时,router.ko 只需使用适当的虚拟设备调用适当的 add_device 方法。 router.ko 还应该导出 dev_A 和 dev_B 模块可用于访问底层硬件的方法。
对于我想到的示例,您可以查看上游内核中的 mlx4_core、mlx4_ib 和 mlx4_en 模块(我编写了它们,所以我选择这个示例:)。他们的想法是,有一个 PCI 设备可以同时用作 InfiniBand 和以太网设备;因此mlx4_ib和mlx4_en都使用mlx4_core来发现和访问底层PCI设备。子驱动程序用于询问存在哪些设备的一小段代码位于 drivers/net/mlx4/intf.c 中。
此外,就现有的“设备 A”用户空间界面而言,这应该不是问题。您可以在 dev_A.ko 中实现相同的 ABI,除非有一些您没有提到的复杂情况。
I don't see any problem with your proposed solution of having one router.ko module that talks to the actual hardware, and submodules dev_A.ko and dev_B.ko that talk to router.ko. You just need to have router.ko export a "my_register_driver" function, analogous to the existing pci_register_driver function. You would pass in a structure that has an "id" member and a "add_device" function pointer; dev_A.ko would pass in id="A" and add_device=dev_A_add, and similarly for dev_B.ko.
Then when router.ko comes up, it discovers the hardware and creates virtual devices (your own context structure) for A and B. Then when a submodule comes along, router.ko just calls the appropriate add_device methods with the appropriate virtual device. router.ko should also export methods that the dev_A and dev_B modules can use to access the underlying hardware.
For an example of what I have in mind, you can look at the mlx4_core, mlx4_ib and mlx4_en modules in the upstream kernel (I wrote them so I choose this example :). The idea with them is that there is one PCI device that can be used as both an InfiniBand and Ethernet device; so mlx4_ib and mlx4_en both use mlx4_core to discover and access the underlying PCI device. The small bit of code that the sub-drivers use to ask for which devices exist is in drivers/net/mlx4/intf.c.
Also, as far as the existing "Device A" userspace interface, that shouldn't be a problem. You can just implement the same ABI in your dev_A.ko, unless there is some complication you didn't mention.