gpt4 book ai didi

macos - 如何在 USBDriverKit 驱动程序和客户端应用程序之间进行通信?

转载 作者:行者123 更新时间:2023-12-02 18:06:58 25 4
gpt4 key购买 nike

我们正在 macOS 上试验 DriverKit,而 DriverKit 在 iPadOS 上仍处于测试阶段。我们想为 iPad 构建一个驱动程序,允许我们的 iPad 应用程序与 USB 设备进行通信。

我们做了什么:

  1. 配置并实现了一个使用 USBDriverKit::IOUSBHostInterface 作为提供者的驱动程序。当我们将设备插入 USB 端口时,macOS 会自动匹配/启动此驱动程序。接下来,我们利用 USBDriverKit::IOUSBHostPipe 从我们的设备发送/接收数据。我们现在在日志中打印设备数据。
  2. 学习 Communicating Between a DriverKit Extension and a Client App
  3. 配置并实现了一个基于 IOUserClient 的驱动程序,并允许 macOs 应用使用 IOServiceOpen API 打开通信 channel 。驱动程序具有将数据传递给 macOS 客户端应用程序的回调。

目前我们想要组合 2 个驱动程序并使用回调将从 USB 设备接收到的数据传递给我们的客户端应用程序。不幸的是,我们卡住了,因为现在我们有 2 个驱动程序实例:

  1. 第一个实例在插入设备时由 macOS 自动运行
  2. 第二个实例是在我们从客户端应用连接时创建的,virtual kern_return_t NewUserClient(uint32_t type, IOUserClient** userClient) 方法被调用。

所以我们不能使用第二个实例进行 USB 设备通信,因为它在 kern_return_t Start(IOService * provider) 中有错误的 provider(IOUserClient) 但我们需要 IOUSBHostInterface开始:

    ivars->interface = OSDynamicCast(IOUSBHostInterface, provider);
    if(ivars->interface == NULL) {
        ret = kIOReturnNoDevice;
        goto Exit;
    }

我们做错了吗?也许我们应该从 UserClient 驱动程序手动执行或使用其他方法,而不是自动匹配 IOUSBHostInterface

据我们了解,我们必须在 NewUserClient 方法中创建一个新的服务实例,并且不能返回操作系统运行的驱动程序:

kern_return_t IMPL(MyDriver, NewUserClient)
{
    kern_return_t ret = kIOReturnSuccess;
    IOService* client = nullptr;
    ret = Create(this, "UserClientProperties", &client);

    if (ret != kIOReturnSuccess)
    {
        goto Exit;
    }

    *userClient = OSDynamicCast(IOUserClient, client);

    if (*userClient == NULL)
    {
        client->release();
        ret = kIOReturnError;
        goto Exit;
    }
Exit:
    return ret;
}

顺便说一句,也许有更简单的方法将数据从 USB 设备转发到 iPadOS 应用程序?

最佳答案

我不知道 USBDriverKit 和 iPadOS,但也许我在 macOS 上使用 PCIDriverKit 的有限经验可以作为一个有用的类比。

我已经为自定义 PCI 设备实现了 DEXT,以及与驱动程序通信以对设备执行操作的用户空间应用程序。

DEXT由两个类组成(两对.iig.cpp文件):

  • 类 MyDriver:公共(public) IOService
  • 类 MyDriverClient: public IOUserClient

使用以下 Info.plist:

<dict>
<key>IOKitPersonalities</key>
<dict>
<key>MyDriver</key>
<dict>
<key>CFBundleIdentifierKernel</key <string>com.apple.kpi.iokit</string>
<key>IOClass</key> <string>IOUserService</string>
<key>IOPCIMatch</key> <string>0xcafebabe</string>
<key>IOPCITunnelCompatible</key> <true/>
<key>IOProviderClass</key> <string>IOPCIDevice</string>
<key>IOUserClass</key> <string>MyDriver</string>
<key>IOUserServerName</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>MyDriverClientProperties</key>
<dict>
<key>IOClass</key>
<string>IOUserUserClient</string>
<key>IOUserClass</key>
<string>MyDriverClient</string>
</dict>
</dict>
</dict>
</dict>

当系统根据 IOPCIMatch 属性值发现具有匹配供应商/设备 ID 的 PCI 设备时,它:

  1. 在内核中实例化一个 IOUserService 类(由 IOClass 属性指定)以促进与驻留在用户空间中的 DEXT 的通信
  2. 为 DEXT 生成用户空间进程。
  3. 在该过程中实例化所需的提供程序类(此处:根据 IOProviderClass 属性的 IOPCIDevice)。
  4. 根据 IOUserClass 属性实例化主类(此处:MyDriver),为其提供指向上面创建的 provider 的指针。

作为其Start 实现的一部分,MyDriver 调用RegisterService()使自己出现在 I/O 注册表中(例如 ioreg -l)。

当用户空间应用程序(具有适当的权利)稍后找到已注册的 MyDriver 服务(例如使用 IOServiceGetMatchingService() )并打开它( IOServiceOpen() )时,在最终调用的 DEXT 端MyDriver::NewUserClient() ( docs ),如下所示:

kern_return_t IMPL(MyDriver, NewUserClient)
{
kern_return_t ret = kIOReturnSuccess;
IOService* client = nullptr;

ret = Create(this, "MyDriverClientProperties", &client);
// ... Error handling

*userClient = OSDynamicCast(IOUserClient, client);
// ... Error handling

// If you need to remember/keep track of the client, you could stash it in the `ivars`, already casted to its true type:
ivars->client = OSDynamicCast(MyDriverClient, client);

// ...
}

到底是什么Create将执行的操作由提供的属性字典决定(在 Info.plist 中任意命名的 MyDriverClientProperties 键下)。在这种情况下,一个 IOUserUserClient (双 User 不是拼写错误) 对象在内核中创建(IOClass 属性),并在用户空间(IOUserClass 属性)中创建一个 MyDriverClient 对象。

您在问题中的描述似乎另有说明,但至少在我的情况下,客户端对象被提供给 MyDriver 实例作为其 provider,我能够获取对它的引用:

kern_return_t IMPL(MyDriverClient, Start)
{
kern_return_t ret;
ret = Start(provider, SUPERDISPATCH);
// ... Error handling

ivars->driver = OSDynamicCast(MyDriver, provider);
// ... Error handling

// ...
}

稍后,当调用 MyDriverClient::ExternalMethod ( docs ) 时,我可以使用 ivars->driver 来调用 MyDriver 的功能 类并与底层设备交互。

关于macos - 如何在 USBDriverKit 驱动程序和客户端应用程序之间进行通信?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73043872/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com