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.
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
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
We added a packet filter to our app, then found a way to not need it, so we want to be able to remove it on upgrades. But we don't want to install it if it's not already installed. Simple, right?
The basic flow of the code is, on start-up, it does a propertiesRequestForExtensiion request. The method for the delegate goes through the various versions, ignoring any that are property.isEnabled == NO. When it comes to one that is enabled, it checks the version -- if it's the same version as the running app, it goes to deactivate it. If it's a different version, it goes to enable the current version (creating a activationRequestForExtensiion request).
This should all be very simple. Except.
At some point during this, the properties request gets a failure -- Domain=OSSystemExtensionErrorDomain Code=1. Ok, it seems there are lots of them laying around (I haven't rebooted in a while), and that method doesn't return once it finds one that is enabled. So maybe it doesn't like that.
And then the activation request that was submitted also fails, also with the same error that doesn't explain anything.
I thought, ok, maybe they don't like to stop on each other's toes, so let's create a serial dispatch queue, and have all of the system extension requests use that queue. That way, the activation request won't begin until the properties request has finished!
Only I did that. And it did get a bit further -- the request method was invoked! Only then I still got messages about the properties and activation requests failing with the same unknown error.
So then I looked at console. And sysextd is crashing, every time this happens. And then I dump all of the logs around that time, and look through them, and see... nothing.
I had hoped to end this with a description of how I achieved victory, but instead... I'm going to have to reboot and see if that solves the mysterious crashing of sysextd.
How does VMWare access USB devices without have any specifics of the USB device? Does it use the same profile/entitlement process or does it take a different approach?
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
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)
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!