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)
Drivers
RSS for tagUnderstand the role of drivers in bridging the gap between software and hardware, ensuring smooth hardware functionality.
Post
Replies
Boosts
Views
Activity
We have been doing a R&D work related to the NVMe controller on Mac platform, where we need to get control of the admin queues(submission as well as completion). From the spec of NVMe it’s very clear that what are all registers do we need to deal with to get access of the queues. We are accordingly following those registers to create our own queues. Also we have prepared and enqueued a sample admin command to the newly created submission queue. But surprisingly we can’t get any assurance whether the command got processed by the controller or not, because from the completion queue entry we can see all the entries are zero, which is not expected anyway. So here the question is, how to communicate with the controller properly ? We are also aware of the fact of existing NVMe driver(IONVMeFamily) on Mac platform, is this somehow crossing our way ? We have done all the proper setup for registers, DMAs and interrupt. Path is very ok if we use builtin driver with the XNVME user space application (we can trigger limited admin commands over there). But here we need to have our own created queues up and running with seamless admin command transaction. Here we must tell about our setup, we have one SSD which is connected via a thunderbolt cable to Mac laptop using type C usb port. We have tried to access pre-configured admin queues from IONVMeFamily driver but that is also a blocker for us, as we can’t see any valid data from submission/completion queues.
Request you to all please help us coming out of this trapped zone.
I'm working on hardware that communicates wireless and wired with mobile systems. Anything non-i[Pad]OS we can connect via USB and achieve great bandwidth, in situations where this is necessary.
Since i[pad]OS does not support FTDI class compliant devices through USB (and also omits the IOUSB framework), I wonder whether we have a way to "work around" this, e.g. how about (ab)using another protocol that i[pad]OS allows?
Concretely, would you think it's possible to tunnel our serial data stream via USBHID?
Hardware and software configuration
MacBook Air M2 2022 16GB,
MacOS Ventura 13.2.1
Full description
This is a DriverKit that controls PCIE FPGA devices for low-latency data exchange.
This driver has been implemented on Iokit, and now it needs to be launched on Driverkit to adapt to newer Macs.
Driverkit lacks the IOMemoryDescriptor::withAddressRange(Iokit) function to convert the app's memory of any size to a Descriptor.
Currently, we use args->structureOutputDescriptor->CreateMapping to map the Descriptor passed by the application to the kernel layer.
// App
size_t ***::xxRead(long long addr, size_t size, void * buff){
std::lock_guard<std::mutex> guard(usrLock);
kern_return_t kr;
uint64_t info[2] = {(uint64_t)addr, (uint64_t)size};
kr = IOConnectCallMethod(
connect,
kUserReadIO,
info,
2,
NULL, NULL, NULL, NULL,
buff,
&size);
return size;
}
// Driverkit
const IOUserClientMethodDispatch sMethods[kNumMethods] = {
[kUserReadIO] =
{
(IOUserClientMethodFunction) &SmiPcieUc::sUserReadIo,
.checkCompletionExists = false,
.checkScalarInputCount = 2, // Read Addr, size
.checkStructureInputSize = 0,
.checkScalarOutputCount = 0,
.checkStructureOutputSize = kIOUserClientVariableStructureSize} // Read Data
};
kern_return_t SmiPcieUc::sUserReadIo (OSObject * target, void* reference, IOUserClientMethodArguments* args){
IOMemoryMap * memMap = nullptr;
uint32_t * buffKptr = nullptr;
kern_return_t rt = 0;
if(target == nullptr){
Log("***Err***: sUserReadIo Target is Null!");
return kIOReturnError;
}
if(args->structureOutputDescriptor){
rt = args->structureOutputDescriptor->CreateMapping(0,0,0,0,0, &memMap);
if(rt == kIOReturnSuccess){
buffKptr = reinterpret_cast<uint32_t *>(memMap->GetAddress());
}
else {
Log("***Err***: sUserReadIo Mapping Failed!");
return kIOReturnNoMemory;
}
} else {
buffKptr = (uint32_t *) args->structureOutput;
}
rt = ((SmiPcieUc *)target)->UserReadIo((uint64_t *)&args->scalarInput[0], (size_t *)&args->scalarInput[1], buffKptr);
OSSafeReleaseNULL(memMap);
return rt;
}
phenomenon
When StructureOutputSize is greater than 4096, args>structureOutputDescriptor exists, and when it is less than or equal to 4096, args->structureOutputDescriptor and args->structureOutput are both equal to nullptr, (in IOkit, args->structureOutput is not empty)。
How to properly convert any size of application memory into the kernel space of Driverkit?
Greetings.
I'm trying to build an Apple Silicon driver for a Roland keyboard which is no longer supported by the manufacturer. The most recent official driver is from 2010.
From my limited understanding of the Apple documentation, it seems to be telling me that I need to build a codeless dext which overrides some sort of base class.
The keyboard uses bog standard USB 1.0 to communicate with the host. Total newb in the driver area so if anyone could point me in the right direction on where to start I would be totally grateful.
When the product of USB drive we made connected to iPhone 15, what should we set for TransportComponentName? Should we set ‘USB Connector’ for TransportComponentName? The default value is 'Lightning Connector' before. But how about the Type-C port of iPhone 15 now?
I have an app that loads a DEXT (driver). This app includes a settings bundle that allows me to activate/deactivate the driver. When I issue the API call to activate the driver, iOS switches to the Settings app and displays the page for my DEXT loading application but the switch to enable the driver, which is part of my settings bundle, does not appear.
I'm using this API call:
OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: "driver-id", queue: .main)
Here are the contents of my settings bundle Root.plist:
`
Here are the contents of my Root.strings file:
"Group" = "Group"; "Name" = "Name"; "none given" = "none given"; "Enabled" = "Enabled";
I am trying to implement the Sanitize and Firmware Upgrade commands for an external card connected via the Thunderbolt Interface (4.0)
Should we consider writing a Kext based off IOBlockStorageDriver or IOPCI interface.
NVMController does not expose anything more than the 3 API.. SmartReadData, getLogData and getIdentifyData.
The device is connected only on MacOS.(mini and macbooks)
My ioregistry look like :
| | | +-o DSB1@1 <class IOPCIDevice, id 0x1000003dc, registered, matched, active, busy 0 (194 ms), retain 14>
| | | | +-o IOPP <class IOPCI2PCIBridge, id 0x100000457, registered, matched, active, busy 0 (182 ms), retain 8>
| | | | +-o UPS0@0 <class IOPCIDevice, id 0x1000003e0, registered, matched, active, busy 0 (182 ms), retain 17>
| | | | +-o IOPP <class IOPCI2PCIBridge, id 0x100000477, registered, matched, active, busy 0 (181 ms), retain 8>
| | | | +-o pci-bridge@0 <class IOPCIDevice, id 0x1000003e1, registered, matched, active, busy 0 (181 ms), retain 11>
| | | | +-o IOPP <class IOPCI2PCIBridge, id 0x10000047d, registered, matched, active, busy 0 (180 ms), retain 8>
| | | | +-o pci1987,5021@0 <class IOPCIDevice, id 0x1000003e2, registered, matched, active, busy 0 (180 ms), retain 12>
| | | | +-o IONVMeController <class IONVMeController, id 0x100000486, registered, matched, active, busy 0 (166 ms), retain 11>
| | | | +-o IONVMeBlockStorageDevice@1 <class IONVMeBlockStorageDevice, id 0x10000048c, registered, matched, active, busy 0 (166 ms), retain 11>
| | | | +-o IOBlockStorageDriver <class IOBlockStorageDriver, id 0x10000048d, registered, matched, active, busy 0 (166 ms), retain 8>
| | | | +-o Prograde Digital Media <class IOMedia, id 0x10000048e, registered, matched, active, busy 0 (166 ms), retain 12>
| | | | +-o IOMediaBSDClient <class IOMediaBSDClient, id 0x100000490, registered, matched, active, busy 0 (0 ms), retain 6>
| | | | +-o IOGUIDPartitionScheme <class IOGUIDPartitionScheme, id 0x100000492, !registered, !matched, active, busy 0 (0 ms), retain 7>
| | | | +-o EFI System Partition@1 <class IOMedia, id 0x1000004d7, registered, matched, active, busy 0 (0 ms), retain 10>
| | | | | +-o IOMediaBSDClient <class IOMediaBSDClient, id 0x1000004db, registered, matched, active, busy 0 (0 ms), retain 6>
| | | | +-o Untitled 2@2 <class IOMedia, id 0x1000004d9, registered, matched, active, busy 0 (0 ms), retain 11>
| | | | +-o IOMediaBSDClient <class IOMediaBSDClient, id 0x1000004df, registered, matched, active, busy 0 (0 ms), retain 7>Any pointers on this would be helpful.
I would like to detect audio input device state change in system logs. Right now i can detect the activation using:
log show
--info
--predicate
"process == 'coreaudiod' && category == 'access'".
But i'm unable to detect deactivation and have no idea which predicate to use.
I searched for MFi's authentication information, but did not specify the need to add an MFI chip to the USB-C interface. Have you resolved the communication issue between the APP and external USBC?
The link is as follows:
app store: monitor+
I have checked the header file for USB in the IOKit framework of macOS, but it does not exist in iOS.
Is it necessary to collaborate with Apple to implement functions similar to monitor+(PTP control camera)?
Hi, does anyone know if IOUSBDeviceInterface187 and IOUSBInterfaceInterface190 interfaces will be available on application level next years and there is no any deprecation plans ?
Common Recommendations are to use USBDriverKit, but is there a real need to complicate USB communication in this way?
I am using SCSIPeripheralsDriverKit/IOUserSCSIPeripheralDeviceType00 to develop a Dext driver, which has only two classes: MyUserSCSIPeripheralDeviceType00 and MyUserClient,
MyUserClient is responsible for receiving APP commands and passing them to MyUserSCSIPeripheralDeviceType00->UserSendCDB(),
After the device is connected to the computer, the driver can match the device and start, calling MyUserSCSIPeripheralDeviceType00-->init(), MyUserSCSIPeripheralDeviceType00-->Start(),
Any command sent by the APP to MyUserSCSIPeripheralDeviceType00 will return a failure: kIOReturnUnsupported (0xe00002c7), including UserSendCDB(), UserReportMediumBlockSize(),
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IOKitPersonalities</key>
<dict>
<key>MySCSIDriver</key>
<dict>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleIdentifierKernel</key>
<string>com.apple.kpi.iokit</string>
<key>IOClass</key>
<string>IOUserService</string>
<key>IOMatchCategory</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>IOProviderClass</key>
<string>IOSCSIPeripheralDeviceNub</string>
<key>IOResourceMatch</key>
<string>IOKit</string>
<key>IOUserClass</key>
<string>MyUserSCSIPeripheralDeviceType00</string>
<key>IOUserServerName</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>UserClientProperties</key>
<dict>
<key>IOClass</key>
<string>IOUserUserClient</string>
<key>IOUserClass</key>
<string>MyUserClient</string>
</dict>
<key>bConfigurationValue</key>
<integer>1</integer>
<key>bInterfaceNumber</key>
<integer>0</integer>
<key>bcdDevice</key>
<integer>1</integer>
<key>idProduct</key>
<string>*</string>
<key>idVendor</key>
<integer>12345</integer>
<key>Peripheral Device Type</key>
<integer>0</integer>
<key>IOKitDebug</key>
<integer>65535</integer>
</dict>
</dict>
</dict>
</plist>
This is the method that receives client calls
kern_return_t MyUserSCSIPeripheralDeviceType00::HandleExternalStruct(IOUserClientMethodArguments* arguments)
{
kern_return_t ret = kIOReturnSuccess;
SCSIType00OutParameters command;
SCSIType00InParameters response;
SCSI_Sense_Data sense;
UInt64 fSenseAddr = (intptr_t)&sense;
bzero((void *)&command, sizeof(SCSIType00OutParameters));
bzero((void *)&response, sizeof(SCSIType00InParameters));
bool test = TEST_UNIT_READY(&command, &response, fSenseAddr);
// test is true
ret = this->UserSendCDB(command, &response);
// ret is kIOReturnUnsupported (0xe00002c7)
UInt64 blockSize;
kern_return_t sizeRet = this->UserReportMediumBlockSize(&blockSize);
// sizeRet is kIOReturnUnsupported (0xe00002c7)
};
// Not called. As per the documentation, this should be called during enumeration.
kern_return_t IMPL(I4UserSCSIPeripheralDeviceType00, UserDetermineDeviceCharacteristics)
{
//
*result = true;
return kIOReturnSuccess;
}
The only one I can find it are some code comments in head files, would like to know any detialed workflow or sample code for it.
Thanks!
How can a Dext be activated from C++. Specifically we need to load our Dext from our c++ CoreAudio server plugin.
I guess it all boils down to how to call the OSSystemExtensionRequest Swift interface from C++...
Thanks for any hints!
Using IOServiceMatching and IOServiceGetMatchingServices api's written in swift to extract the info of both internal and external USB devices connected.
For the same code Intel based Mac OS devices gives all the info like product id , vendor id , Serial number and etc for both external and Internal USB devices( Apple and Non Apple devices connected either to Apple T2 bus or USB bus).
For the same code M2 Mac Machine only gives the external device info which are connected to USB, doesn't give any info of Internal USB connected devices.
Why is this difference ? Which api's need to be used to extract info of internal USB connected devices even in M2 based Mac machine.
Thanks
We have developed a library and a DriverKit driver on Mac platform. And we need to disable SIP to install dext and later point of time if we enable SIP then the dext is non functional. So is it mandatory to disable the SIP for whole life time of dext? Also it is not recommended to disable the SIP for a long time, as it may create a security hole.
Standard ways are given on Apple support page that how to notarise an application to distribute over the internet. Here one mandatory account is required that is Apple Developer account which is a paid account we believe. Standing at this point can you share the complete steps of software distribution process which will include code signing, notarisation process and stapling.
Hi. I am new to ios development and I am using swift to try to develop a sample app to connect a Canon camera to an iphone via a usb cable and I want to use the ImageCaptureCore framework to do this (that is I want to use the USB PTP). Although I see the documentation on the Apple site, I am still unsure where to begin. Is there any tutorials, etc. about where I can get started with this? I was able to find a couple of code snipets and piece together something with ICDeviceBrowser but when I load the program onto my iphone and connect the camera via usb, I am not able to detect any camera. So ideally I am looking for some sort of tutorial that goes through how to do this or if not, what do I have to do to at least be able to detect the camera from the iphone?
Hi everyone,
first-time caller, long-ti... wait, no, I just got here. :)
I am relatively new to all things Apple, so apologies in advance if it takes me a few goes to properly explain things.
We have a framework, which includes an API, an XPC service, etc, and we have a device driver. We also have some sample apps that use the framework, and if they have the app sandbox capability, then we expect them to use the XPC Service instead of accessing our driver directly. This works fine on Monterey and presumably has worked fine on all previous versions of MacOS.
Something seems to have changed on Ventura, and we don't understand what.
When we build the same app on Ventura, it appears to be in the sandbox (according to the Sandbox column in Activity Monitor), but in the Console there is this line (twice):
default <time> <OurAppName> Revoking sandbox extension; key = 0
Which we suspect is linked to the fact that the app then does not use the XPC Service, and instead accesses the driver directly, much to our surprise.
Software built on developer's machines is "Automatically managed" and "Signed to Run Locally" in case that matters.
Do we need to change our code to support Ventura and onward? Or is it a bizarre bug?
Oh, I should say that I'm running the latest version of Ventura (13.6.7 as of writing) but not the latest Xcode (14.2 (14C18)) and CLI tools... can't remember how to find that version... Apple clang version 14.0.0 (clang-1400.0.29.202).
Any help would be appreciated, thanks.
Jeremy
Hello.
Is there a legal way to block iOS devices from being mounted on macOS?
I noticed, that when an iOS device is connected, it pretends to be like a storage device but it is not. It not even going through diskArbitration. It seems that some fileProvider is taking place there.
I know that it is possible to do via the MDM profile:
<key>PayloadContent</key>
<dict>
<key>.GlobalPreferences</key>
<dict>
<key>Forced</key>
<array>
<dict>
<key>mcx_preference_settings</key>
<dict>
<key>ignore-devices</key> <true/>
</dict>
</dict>
</array>
</dict>
</dict>
But is there some programmatic solution?
If I use EndpointSecurity and block file operations for the usbmuxd process on /var folder, it prevents iOS devices from being mounted. But wouldn't be there any negative side effects from such a solution?