We are experimenting with DriverKit on macOS while DriverKit is still in beta on iPadOS. We want to build a Driver for iPad that will allow to communicate our iPad App with USB device.
What we did:
- Configured and implemented a driver that uses
USBDriverKit::IOUSBHostInterface
as provider. This driver is automatically matched/started by macOS when we plug our device into USB port. Next we utilisedUSBDriverKit::IOUSBHostPipe
to send/receive data from our device. We print data from device in logs for now. - Studied Communicating Between a DriverKit Extension and a Client App
- Configured and implemented a driver that based on
IOUserClient
and allows to open communication channel by macOs App usingIOServiceOpen
API. Driver has callback to pass data to macOS Client App.
Currently we want to combine 2 drivers and pass data received from USB device to our client App using callback. Unfortunately, we stuck since now we have 2 instances of driver:
- First instance is automatically run by macOS when device is plugged
- Second instance is created when we are connecting from Client App and
virtual kern_return_t NewUserClient(uint32_t type, IOUserClient** userClient)
method is called.
So we can't use second instance to do USB device communication since it has wrong provider(IOUserClient) in kern_return_t Start(IOService * provider)
but we need IOUSBHostInterface
to start:
ivars->interface = OSDynamicCast(IOUSBHostInterface, provider);
if(ivars->interface == NULL) {
ret = kIOReturnNoDevice;
goto Exit;
}
Are we doing it wrong? Maybe instead of automatic matching for IOUSBHostInterface
we should do it manually from UserClient driver or use another approach?
As we learned we have to create a new service instance in NewUserClient
method and can't return driver that was run by OS:
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;
}
BTW, maybe there is much easier way to forward data from USB device to iPadOS App?