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)
DriverKit
RSS for tagDevelop device drivers that run in user space using DriverKit.
Posts under DriverKit tag
59 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hi,I am trying to write Dext code for my existing Kext,How to convert this code to be compatible with Dext?
BufferMemoryDescriptorAME_Module = NULL;
IOMemoryMap *MemMap;
BufferMemoryDescriptorAME_Module= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task,kIOMemoryPhysicallyContiguous,otal_memory_size);
BufferMemoryDescriptorAME_Module->prepare(kIODirectionInOut);
MemMap = BufferMemoryDescriptorAME_Module->map(kIOMapInhibitCache);
logicalAddressAME_Module = (UInt8 *) MemMap->getVirtualAddress();
physicalAddressAME_Module = MemMap->getPhysicalAddress();
Thanks,
Frederic
Hello! I'm trying to get data (like audio) stream from custom vendor usb device with bulk endpoint. When I use AsyncIO in cycle some data was lost. And I saw that AsyncIOBundled can help me with this issue.
I've trying to use it:
Create memory buffers
for (int i = 0; i < DEFAULT_BUF_NUMBER; i++) {
kern_return_t ret = IOBufferMemoryDescriptor::Create(
kIOMemoryDirectionInOut,
DEFAULT_BUF_LENGTH,
0,
&ivars->buffers[i]
);
}
Create MemoryDescriptorRing and set MemoryDescriptor for each index
kern_return_t MyDriver::SetupRingBuffer(IOMemoryDescriptor** memoryDescriptors, uint16_t length)
{
kern_return_t ret = kIOReturnSuccess;
ret = ivars->inPipe->CreateMemoryDescriptorRing(length);
if (ret != kIOReturnSuccess) {
IOLog("CreateMemoryDescriptorRing failed %s", StringFromReturn(ret));
return ret;
}
for (int i = 0; i < length; i++) {
ret = ivars->inPipe->SetMemoryDescriptor(memoryDescriptors[i], i);
if (ret != kIOReturnSuccess) {
IOLog("SetMemoryDescriptor failed %s", StringFromReturn(ret));
break;
}
}
return ret;
}
Create completion
Run AsyncIOBundled for only 1 index
ret = ivars->inPipe->AsyncIOBundled(
i,
1,
&transferAccepted,
(const unsigned int *)&ivars->dataBufferLengthArray,
DEFAULT_BUF_NUMBER,
ivars->readBundledCompletion,
0
);
In completion i'm always get the error 0xe0005000 (UNDEFINED)
But if I use AsyncIO with same buffer - it's success.
What am I doing wrong? There are no differences btw AsyncIOBundled and AsyncIO requests in wireshark
I am using a Silicon labs CP2102 chip. I have configured a custom USB VID and PID on the chip, and want to create a MacOs driver (or rather map this custom VID/PID to an existing driver) to make it accessible as a USB serial device from my Mac.
Preferably I'd like to map my device to the com.apple.DriverKit-AppleUSBSLCOM.dext driver, but I think the generic USB serial driver (com.apple.DriverKit-AppleUSBSerial.dext) should work too. Silabs also has their own driver (com.silabs.cp210x.dext, downloadable from their web page), if for some reason it is easier to map to that than to one of the native drivers that could also work.
Based on
https://developer.apple.com/documentation/kernel/implementing_drivers_system_extensions_and_kexts#3616855
and
https://developer.apple.com/documentation/driverkit/creating_a_driver_using_the_driverkit_sdk
it should be possible to create a codeless dext, which just inherits from e.g. IOUserUSBSerial.
I've tried both creating just a DriverKit driver and putting it under /Library/DriverExtensions/ and creating a (default) app and adding a DriverKit driver to it, and putting the app in my /Applications/ folder, but neither works for me.
My driver implementation is just this:
#include <USBSerialDriverKit/IOUserUSBSerial.iig>
class MyDriver: public IOUserUSBSerial
{
};
and my IOKitPersonalities looks like this:
<key>IOKitPersonalities</key>
<dict>
<key>MyDriver</key>
<dict>
<key>CFBundleIdentifier</key>
<string>com.mydriver.MyDriverApp.MyDriver</string>
<key>IOClass</key>
<string>IOUserUSBSerial</string>
<key>IOMatchCategory</key>
<string>com.mydriver.MyDriverApp.MyDriver</string>
<key>IOProviderClass</key>
<string>IOUSBHostInterface</string>
<key>IOUserClass</key>
<string>MyDriver</string>
<key>IOUserServerName</key>
<string>com.mydriver.MyDriverApp.MyDriver</string>
<key>bConfigurationValue</key>
<integer>1</integer>
<key>bInterfaceNumber</key>
<integer>0</integer>
<key>idProduct</key>
<integer>(my custom PID, decimal value)</integer>
<key>idVendor</key>
<integer>(my custom VID, decimal value)</integer>
</dict>
</dict>
I've disabled SIP and enabled developer mode (systemextensionsctl developer on), though I'm not sure if it's needed. I've scanned through the system logs and looked at the ioreg output. When I connect a CP2102 chip with default VID and PID, I can see that it maps to the native com.apple.DriverKit-AppleUSBSLCOM.dext driver. When I connect the same chip with my custom VID and PID, I don't see any trace of my driver being used. I can see it in the System Information app, but it doesn't map to my driver.
I'm currently suspecting it is an Entitlements issue. In my app I have an Entitlements file, where I've added DriverKit USB Transport and DriverKit Serial Family. Do I need something like this for the driver target? There is no default Entitlements file there, but maybe I should create one? Or is there something else I'm missing?
I've also noted one odd thing: When I install my app I can see a system log entry, complaining that "package type not SYSX" (for my driver). But I don't think it should be a SYSX package? It's currently specified as a DEXT package.
I'm looking for a fast and efficient way for user-space to send I/O to my driver. One way I'd have hoped to do this, was through a shared memory ring-buffer.
In the WWDC19 presentation on System Extensions and DriverKit, at roughly 17:00, they mention an IOSharedDataQueueDispatchSource. This doesn't exist in the DriverKit API. An IODataQueueDispatchSource is available, but doesn't seem to be meant to be shared.
In the old IOKit framework, there are similar IOSharedDataQueue and IODataQueue, but they are unavailable in DriverKit.
So, what are my options for implementing a fast, efficient I/O path to my driver?
Few user space applications are available in market for example xnvme, but does not have any interaction with Admin Submission/Completion queues.
Also IOCTLs are not very prominent . Is there any ways to get access to the native NVMe Mac driver source code?
Thanks, hopefully we will get some positive response here.
this is a repost with more appropriate tags. The original is here:
https://developer.apple.com/forums/thread/744268
Can anyone advise, or give example of, communicating large (>128 byte) incoming buffers from a dext to a user-space app?
My specific situation is interrupt reads from a USB device. These return reports which are too large to fit into the asyncData field of an AsyncCompletion call. Apple's CommunicatingBetweenADriverKitExtensionAndAClientApp sample shows examples of returning a "large" struct, but the example is synchronous. The asynchronous example returns data by copying into a IOUserClientAsyncArgumentsArray, which isn't very big.
I can allocate a single buffer larger than 4K in user space, and communicate that buffer to my driver as an IOMemoryDescriptor when I set up my async callback. The driver retains the descriptor, maps it into its memory space and can thus write into it when the hardware returns interrupt data. The driver then calls AsyncCompletion, which will cause my user-side callback to be called, so the user side software knows that there's new data available in the previously allocated buffer.
That's fine, it works, but there are data race problems - since USB interrupt reads complete whenever the hardware has provided data, incoming completions happen at unpredictable times, so the shared buffer contents could change while the user side code is examining them.
Is there an example somewhere of how to deal with this? Can I allocate memory on the driver side on demand, create an IOMemoryDescriptor for it and return that descriptor packed inside the asyncData? If so, how does the driver know when it can relinquish that memory? I have a feeling there's something here I just don't understand...
I'm currently working on developing a PCI driver using PCIDriverKit, but I'm encountering challenges, particularly with the driver's extension. I need some insights on the APIs and methods to follow the best practices in generating PCI drivers for retrieving PCI devices information and running NVMe commands on the devices.
I am new to macOS development and presently tearing my hair out trying to get a driverkit extension to build. I have tried following the instructions here:
https://developer.apple.com/documentation/driverkit/communicating_between_a_driverkit_extension_and_a_client_app
namely, disabling SIP, but I am still unable to get my extension to build. The instructions say to set the code signing identity to "Sign to Run Locally" for all three targets, but this is not listed as an option for the driver extension.
This is the official documentation for DriverKit testing.
https://developer.apple.com/documentation/driverkit/debugging_and_testing_system_extensions
I followed the docs and turned off SIP, turned on developer mode, and changed Xcode to manual signing and specified it as a signature from my local keychain.
Then I click "Run" in Xcode, and I get this error.
Even with local signatures, it still requires a provisioning profile, which is impossible to get.
So, is there any way I can build my code using Xcode 15?
We got an app for iPad which has two targets one for the App itself (MainApp target ) and another one for the Driver ( Driver Target ) using DriverKit.
The app works fine in Development, but I'm trying to distribute it with adhoc.
I've requested the Distribution Entitlement to Apple, after getting it, the App Id for the Driver has the following Capabilities:
DriverKit, DriverKit (development), DriverKit USB Transport (development), DriverKit USB Transport - VendorID, In-App Purchase
Now in the profile section, I've created a adhoc profile for the Driver AppId (Identifier). Obviously I've also created an Adhoc profile for the Main AppId
Finally in the Signing & Capabilities Section I set up the profiles for MainApp target, int the Debug one I set up the Development one and int the Release one I set up the adhoc one.
I do the same in the Driver Target, but when I set up the Adhoc one in the Release, I've got a warning:
Xcode 14 and later requires a DriverKit development profile enabled for iOS and macOS. Visit the developer website to create or download a DriverKit profile
Also interestingly the Signing Certificate section says: None
I also set up the Capabilities for the Driver Target:
DriverKit USB Transport - VendorID
DriverKit USB Transport ( Development )
Inside these capabilities I set up the vendor ID as dictionary
The problem is, if I try to Archive the app I will get the previous Warning message as error:
Xcode 14 and later requires a DriverKit development profile enabled for iOS and macOS. Visit the developer website to create or download a DriverKit profile.
Any idea what I'm missing?
Thanks
I want to get the information of USB like, USB name, size, VID, PID, etc using DriverKit Extension but I'm facing difficulty finding such references or Sample code for the same.
Please help me with the Sample code to get USB info with the help of Dext.
Thanks
I declare a structure type in swift, name as CmdStruct
struct CmdStruct {
var cmd:[UInt8]
init() {
cmd = [UInt8](repeating: 0, count:16)
}
}
In the case that the connection has been obtained.
In sendCmd function, declare a variable which name as input which type of CmdStruct.
After set data to input, call a DriverKit function IOConnectCallStructMethod.
Here xcode shows a warning tip for the parameter 'input' for call IOConnectCallStructMethod:
<Forming 'UnsafeRawPointer' to a variable of type 'CmdStruct'; this is likely incorrect because 'CmdStruct' may contain an object reference.>
func sendCmd() {
var ret:kern_return_t = kIOReturnSuccess
var input = cmdStruct()
var output:[UInt8] = [UInt8](repeating:0, count: 16)
var inputSize = MemoryLayout<CmdStruct>.size // print value 8
var outputSize = output.count // print value 16
input.cmd[0] = 0x12
input.cmd[1] = 0x34
ret = IOConnectCallStructMethod(Connection, selector, &input, inputSize, &output, &outputSize)
}
In C file, driverkit function ExternalMethod will receive the parameter from swift side.
And check the value of input->cmd[0] and input->cmd[1] in console. However, the values are not the expected 0x12 and 0x34.
struct CmdStruct
{
uint8_t cmd[16];
};
kern_return_t myTest::ExternalMethod(uint64_t selector, IOUserClientMethodArguments* arguments, const IOuserClientMethodDispatch* dispatch, OSObject* target, void* reference)
{
int i = 0;
CmdStruct* input = nullptr;
if (arguments == nullptr) {
ret = KIOReturnBadArgument;
}
if (arguments->structureInput != nullptr) {
input = (CmdStruct*)arguments->structureInput->getBytestNoCopy();
}
/*
Here to print input->cmd[0] and input->cmd[1] data to console.
*/
}
I expect that the correct value of input will be show on the driverkit side. I'm not sure which part is wrong. Here, I list some factors that may lead to incorrect value.
How to fix the warning tip for parameter 'input' when call IOConnectCallStructMethod in swift.
I get the inputSize value 8 by using MemoryLayout.size. But this structure contains a 16 bytes array. How to get the correct struct size in swift
In C file side, using (CmdStruct*)arguments->structureInput->getBytestNoCopy() to transform data to C struct is correct?
I am currently in the process of developing a DEXT for a USB based external mass storage device using the USBDriverKit framework. IOUSBHostInterface is used as the provider to communicate with the interface's endpoints and I am successful in it. As per the IOUSBHostInterface documentation,
To use a host interface object, call Open to create a new session between the interface and your driver. After successfully opening your session, you can request information from the interface and set up pipes to communicate with the interface's endpoints. Remember to close the session you opened in the Stop method of your driver.
However, calling Open gains exclusive access to the USB interface and does not allow other services to access the interface. Also, to let go of the exclusive access, Close method can be called but in the Stop method which is called only once during the lifecycle of the extension (when the DEXT is unloaded).
As a result of this, Apple's mass storage related KEXTs (media and partition related specifically) do not match the interface and so the filesystem of the drive in question does not get mounted whenever the DEXT has matched the interface.
Is this exclusive access a limitation of USBDriverkit or is there any way to get around this issue in this case?
In a project, I'm using the DriverKit(and HIDDriverKit) framework.
I have encountered a problem in the connection between the client app and the driver, which is implemented by the "IOKit" framework.
By calling the function "IOServiceGetMatchingServices" the value of "iterator" returns correctly and then communication with the driver is done.
However, after releasing the version on the TestFlight, on some systems, the value of the "iterator" returned 0 and it is not possible to communicate with the driver.
I checked the status of the activated driver with the command "systemextensionsctl list" and there are no problems on the driver side and the values of "Enabled" and "Active" are starred.
AppSandbox = True, SIP: enable
ret = IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceNameMatching(dextIdentifier), &iterator);
if (ret != kIOReturnSuccess)
{
goto fail;
}
while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) {
ret = IOServiceOpen(service, mach_task_self(), 0, &connection);
if(ret == kIOReturnSuccess)
{
break;
}
else
{
syslog(LOG_WARNING, "IDmelonLog LIB: Can't open service");
}
IOObjectRelease(service);
}
Hi @eskimo! With the introduction of USB-C ports on the newest iPhones, will there be any support for DriverKit (or USBSerialDriverKit 🤞) similar to the USB-C iPads?
We are wanting to enable serial communication with a custom USB peripheral via the new USB-C port. Is this (or will this) be possible in any manor?
Additionally, will this require MFi certification?
Thanks!
I am trying to sign a DriverKit extension for distribution using a Developer ID provisioning profile, but when I try to import the profile to sign the dext I get the error "Platform: MacOS doesn't match platform DriverKit".
We requested the entitlement from Apple a few months ago and according to Apple Support it was approved (though we did not get any email directly from the DriverKit approval process). The App ID we are using appears to have the DriverKit capabilities that we need under "Additional Capabillities".
Our process right now is this:
Go to Certificates, Identifiers, and Profiles
Create a new Provisioning Profile and select Developer ID Distribution
Select the correct App ID
After creating and downloading the profile, import it into Xcode
Receive the error "Platform: MacOS does not match DriverKit"
According to https://developer.apple.com/documentation/driverkit/requesting_entitlements_for_driverkit_development#3557213, there should perhaps be a prompt adding DriverKit to the provisioning profile and not just the identifier, but we do not see this.
Has anybody else run into a similar issue and resolved it? I see a similar thread at https://developer.apple.com/forums/thread/710713, but that one is eight months old and doesn't appear to have a solution.
Hey!
I'am trying to write my own driver for usb serial device. I'am trying to subclass from IOUserUSBSerial
#include <DriverKit/IOService.iig>
#include <USBSerialDriverKit/IOUserUSBSerial.iig>
class NewDriver: public IOUserUSBSerial
{
public:
virtual kern_return_t
Start(IOService * provider) override;
};
but get a lot of errors such as
"IOUserUSBSerial::handleRxPacket(unsigned char*&, unsigned int&)", referenced from:
vtable for NewDriver in NewDriver.iig.o
"IOUserUSBSerial::handleInterruptPacket(unsigned char const*, unsigned int)", referenced from:
vtable for NewDriver in NewDriver.iig.o
"IOUserUSBSerial::free()", referenced from:
vtable for NewDriver in NewDriver.iig.o
"IOUserUSBSerial::init()", referenced from:
vtable for NewDriver in NewDriver.iig.o
"IOUserUSBSerial::initWith(IOBufferMemoryDescriptor*)", referenced from:
vtable for NewDriver in NewDriver.iig.o
"IOUserUSBSerial::_Dispatch(IOUserUSBSerial*, IORPC)", referenced from:
NewDriver::Start_Impl(IOService*) in NewDriver-e6d71af2158103084ce0c1eba7c6088d.o
NewDriver::_Dispatch(NewDriver*, IORPC) in NewDriver.iig.o
"vtable for IOUserSerial", referenced from:
IOUserSerial::IOUserSerial() in NewDriver.iig.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
"vtable for IOUserUSBSerial", referenced from:
IOUserUSBSerial::IOUserUSBSerial() in NewDriver.iig.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
"non-virtual thunk to IOUserUSBSerial::free()", referenced from:
vtable for NewDriver in NewDriver.iig.o
"non-virtual thunk to IOUserUSBSerial::init()", referenced from:
vtable for NewDriver in NewDriver.iig.o
"non-virtual thunk to IOUserUSBSerial::initWith(IOBufferMemoryDescriptor*)", referenced from:
vtable for NewDriver in NewDriver.iig.o
"non-virtual thunk to IOUserUSBSerial::handleRxPacket(unsigned char*&, unsigned int&)", referenced from:
vtable for NewDriver in NewDriver.iig.o
"non-virtual thunk to IOUserUSBSerial::handleInterruptPacket(unsigned char const*, unsigned int)", referenced from:
vtable for NewDriver in NewDriver.iig.o
ld: symbol(s) not found for architecture x86_64
If I making any implementations of this methods errors staying on. What Im doing wrong? Is there anywhere examples for USBSerialDriverKit? Didn't find anything on github
I'm working on a DriverKit driver. I have it running on macOS, including a very simple client app written in SwiftUI. Everything is working fine there. I've added iPadOS as a destination for the app as demonstrated in the WWDC video on DriverKit for iPadOS. The app builds and runs on my iPad, as expected (after a little work to conditionalize out my use of SystemExtensions.framework for installation on macOS). However, after installing and running the app on an iPad, the driver does not show up in Settings->General, nor in the app-specific settings pane triggered by the inclusion of a settings bundle in the app.
I've confirmed that the dext is indeed being included in the app bundle when built for iPadOS (in MyApp.app/SystemExtensions/com.me.MyApp.MyDriver.dext). I also can see in the build log that there's a validation step for the dext, and that seems to be succeeding.
I don't know why the app isn't being discovered -- or in any case surfaced to the user -- when the app is installed on the iPad. Has anyone faced this problem and solved it? Are there ways to troubleshoot installation/discovery of an embedded DriverKit extensions on iOS? Unlike on macOS, I don't really see any relevant console messages.