DriverKit architecture for USB-C device and iPad dext

I am attempting to communicate over serial with a USB-C device and an M-Series iPad. I have proven the device to communicate as expected (baud rate, parity, etc) via a Swift app on Mac using a third party library (IOKit) that utilizes the "AppleUSBACM (v5.0.0)" driver on macOS. I am looking to recreate this communication via iPadOS and a custom DriverKit driver that provides this same interface.

There is not an example from Apple for serial communication and DriverKit but there is a couple for communicating from an app to the dext, and for other networking examples. There are also other mentions in WWDC videos but they are incomplete and do not provide the needed structure.

Communicating between a driver extension and a client app

Connecting a network driver

Bring your driver to iPad with DriverKit

System Extensions and DriverKit

My question revolves around architecture and how to set up a driver for these needs. I have gotten the examples to run and understand what is needed for entitlements and other local signing needs. But what I don't understand is if you need a basic setup similar to the "Communicating between a driver extension and a client app" where your base driver subclasses IOService and has two arms. One that subclasses IOUserclient and allows communication between the dext and your Swift app. And another arm that subclasses IOUserSerial or IOUserUSBSerial. I assume then that these two share buffers of memory set up by the base class that allows communication between the two.

I have had little luck getting IOUserUSBSerial to compile and have made more progress on IOUserSerial. But when running that and with the supposed idVendor plist entry I am not getting that part of the dext to start or recognize when the USB device is plugged in.

Long story short, I'm looking for a basic architecture or example reference to explain serial communication in DriverKit.

Devices:

  • Custom USB-C hardware that is CDC ACM compliant
  • iPad Air 5th gen with M1 chip (iPadOS 17.2)
  • M1 MBP (macOS 14.2.1)
Post not yet marked as solved Up vote post of lgustin Down vote post of lgustin
417 views

Replies

iPadOS only supports a subset of the DriverKit frameworks. That current list is:

https://developer.apple.com/documentation/driverkit/creating_drivers_for_ipados

USBDriverKit
PCIDriverKit
AudioDriverKit

In terms of this question:

But what I don't understand is if you need a basic setup similar to the "Communicating between a driver extension and a client app" where your base driver subclasses IOService and has two arms.

Excluding audio driver, the "basic" architecture for directly communicating with a USB or PCI accessory on iPadOS would be:

  1. A USB or PCI DEXT that matches the relevant accessory and communicates directly with that accessory using the basic bus protocol.
  2. The DEXT implements it's own user client to provide whatever user space communication is necessary.
  3. The final app uses that user client to communicate with the DEXT/accessory.

This is the same "broad" architecture that's used in "Communicating between a driver extension and a client app", however, keep in mind that this sample app directly subclasses IOService because it was the simplest way to demonstrate the basic concept, not because it's actually useful. An actual implementation needs to build of the relevant bus specific base class, otherwise it won't be able to interact with the hardware it's matching.

Related to that point, if you're trying to modify "Communicating between a driver extension and a client app" to work with actual hardware, make sure you check DEXTs "IOKitPersonalities" keys and update them correctly:

https://developer.apple.com/documentation/bundleresources/information_property_list/iokitpersonalities?language=objc

In particularly, leaving "IOClass" as "IOUserService" means the kernel will load "IOUserService" as the supporting class in the kernel. In most cases, that configuration will load, match, and implement the standard DEXT lifecycle, but ALL bus specific methods will be completely non-functional. It an easy issue to overlook and, from past experience, absolutely maddening to try and debug.

-Kevin Elliott
DTS Engineer, CoreOS/Hardware