I am working with USB serial devices on macOS.
How can I detect BSD(unix) name have for my USB Serial device on macOS using IOKit?
I want to get device name like : "IODialinDevice" = "/dev/tty.usbmodemMyDeviceName"
My USB device is USB serial COM port.
Also I want to detect when device was attached to machine.
I can detect when new USB device with my VID and PID was connected.
This code allows me to do it
CFMutableDictionaryRef keywordDict = IOServiceMatching(kIOSerialBSDServiceValue);
kern_return_t result = IOServiceGetMatchingServices(kIOMasterPortDefault, keywordDict, &iterator);
while ((port = IOIteratorNext(iterator)))
{
io_object_t parent = 0;
io_object_t current_device = port;
while (KERN_SUCCESS == IORegistryEntryGetParentEntry(current_device, kIOServicePlane, &parent))
{
CFTypeRef vendor_Id = IORegistryEntryCreateCFProperty(parent, CFSTR(kUSBVendorID), kCFAllocatorDefault, 0);
CFTypeRef pr_Id = IORegistryEntryCreateCFProperty(parent, CFSTR(kUSBProductID), kCFAllocatorDefault, 0);
if((vendor_id==MY_VENDOR_ID) && (pr_ID==MY_PRODUCT_ID))
{
// MY SERIAL DEVICE DETECTED !!
CFTypeRef deviceName = IORegistryEntryCreateCFProperty(device, key, CFSTR(kIOTTYDeviceKey), 0);
CFTypeRef callOutDevice = IORegistryEntryCreateCFProperty(device, key, CFSTR(kIOCalloutDeviceKey), 0);
CFTypeRef dialInDevice = IORegistryEntryCreateCFProperty(device, key, CFSTR(kIODialinDeviceKey), 0);
}
}
}
But the problem that this code not allows me to detect the new device.
I just enumerate existing kIOSerialBSDServiceValue devices here and then I check parents VID and PID
If parent have MY_VID and MY_PID I assume that I have found correct serial device.
Another code allows me to detect new USB device
This is Apple example LUSBPrivateDataSample.c
I can detect my device using VID and PID with the following code
int main()
{
...
...
...
// Create a CFNumber for the idVendor and set the value in the dictionary
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbVendor);
CFDictionarySetValue(matchingDict,
CFSTR(kUSBVendorID),
numberRef);
CFRelease(numberRef);
// Create a CFNumber for the idProduct and set the value in the dictionary
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbProduct);
CFDictionarySetValue(matchingDict,
CFSTR(kUSBProductID),
numberRef);
CFRelease(numberRef);
...
...
...
// Now set up a notification to be called when a device is first matched by I/O Kit.
kr = IOServiceAddMatchingNotification(gNotifyPort, // notifyPort
kIOFirstMatchNotification, // notificationType
matchingDict, // matching
DeviceAdded, // callback
NULL, // refCon
&gAddedIter // notification
);
}
void DeviceAdded(void *refCon, io_iterator_t iterator)
{
io_service_t usbDevice;
while ((usbDevice = IOIteratorNext(iterator)))
{
// I have device here but I can't get IODialinDevice device name
}
}
The problem with this code that I can't get IODialinDevice device name
I have also checked all child nodes for this usbDevice.
None of them contain IODialinDevice property or none of them is kIOSerialBSDServiceValue device.
Looks like I am doing it wrong.
Looks like serial devices and USB live in different IOKit registry branches.
The question is how can go from USB device identified by VID and PID to serial device (kIOSerialBSDServiceValue) with IODialinDevice ("/dev/tty.usbmodemMyDeviceName") property .
This is part of my ioreg tree:
I can detect CDC ACM Data device in my application. (top device in this tree)
In ioreg I see this picture.
So there are children, AppleUSBACMData and IOSerialBSDClient who has IODialinDevice property.
But I can't detect AppleUSBACMData and IOSerialBSDClient in my application .
Probably because AppleUSBACMData and IOSerialBSDClient are not devices, but USB Interfaces or USB Endpoints.
So this is my problem.
+-o CDC ACM Data@3
| {
| "USBPortType" = 0
| "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
| "Product Name" = "DevName"
| "bcdDevice" = 1044
| "USBSpeed" = 3
| "idProduct" = 260
| "bConfigurationValue" = 1
| "bInterfaceSubClass" = 0
| "locationID" = 338886656
| "IOGeneralInterest" = "IOCommand is not serializable"
| "IOServiceLegacyMatchingRegistryID" = 4295561221
| "IOClassNameOverride" = "IOUSBInterface"
| "AppleUSBAlternateServiceRegistryID" = 4295561221
| "idVendor" = 7777
| "bInterfaceProtocol" = 0
| "bAlternateSetting" = 0
| "bInterfaceNumber" = 3
| "bInterfaceClass" = 10
| }
|
+-o AppleUSBACMData
| {
| "IOClass" = "AppleUSBACMData"
| "CFBundleIdentifier" = "com.apple.driver.usb.cdc.acm"
| "IOProviderClass" = "IOUSBHostInterface"
| "IOTTYBaseName" = "usbmodem"
| "idProduct" = 260
| "IOProbeScore" = 49999
| "bInterfaceSubClass" = 0
| "HiddenPort" = Yes
| "IOMatchCategory" = "IODefaultMatchCategory"
| "idVendor" = 7777
| "IOTTYSuffix" = "DevName_B3"
| "bInterfaceClass" = 10
| }
|
+-o IOSerialBSDClient
{
"IOClass" = "IOSerialBSDClient"
"CFBundleIdentifier" = "com.apple.iokit.IOSerialFamily"
"IOProviderClass" = "IOSerialStreamSync"
"IOTTYBaseName" = "usbmodem"
"IOSerialBSDClientType" = "IORS232SerialStream"
"IOProbeScore" = 1000
"IOCalloutDevice" = "/dev/cu.usbmodemDevName_B3"
"IODialinDevice" = "/dev/tty.usbmodemDevName_B3"
"IOMatchCategory" = "IODefaultMatchCategory"
"IOTTYDevice" = "usbmodemDevName_B3"
"IOResourceMatch" = "IOBSD"
"IOTTYSuffix" = "DevName_B3"
}
Any help appreciated!