IOKIT正在检测带有PID和VID的USB串行设备的BSD(unix)名称



我正在macOS上使用USB串行设备。

如何使用IOKit检测macOS上USB串行设备的BSD(unix)名称?我想获得设备名称,如:"IODialinDevice"="/dev/tty.usbmodemMyDeviceName">

我的USB设备是USB串行COM端口。此外,我想检测设备何时连接到机器上。

我可以检测到何时连接了带有我的VID和PID的新USB设备。这个代码允许我做

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);
}
}
}

但是这个代码不允许我检测新设备的问题。我只是在这里列举现有的kIOSerialBSDServiceValue设备,然后检查父设备VID和PID如果父母有MY_VID和MY_PID,我认为我找到了正确的串行设备。

另一个代码允许我检测新的USB设备

这是Apple示例LUSBPrivateDataSample.c我可以使用以下代码使用VID和PID检测我的设备

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 
}
}

此代码的问题是我无法获取IODialinDevice设备名称我还检查了此usbDevice的所有子节点。它们都不包含IODialinDevice属性,或者都不是kIOSerialBSDServiceValue设备。

看来我做错了。看起来串行设备和USB位于不同的IOKit注册表分支中。问题是如何从由VID和PID标识的USB设备转换为具有IODialinDevice("/dev/tty.usbmodemMyDeviceName")属性的串行设备(kIOSerialBSDServiceValue)。

感谢您的帮助!

更新:这是ioreg树:
我可以在我的应用程序中检测CDC ACM数据设备。(此树中的顶部设备)我在里面看到了这张照片。因此,存在具有IODialinDevice属性的子级AppleUSBACMData和IOSerialBSDClient。但我在应用程序中无法检测到AppleUSBACMData和IOSerialBSDClient。可能是因为AppleUSBACMData和IOSerialBSDClient不是设备,而是USB接口或USB端点。所以这就是我的问题。

+-o CDC ACM Data@3  <class IOUSBHostInterface, id 0x100090fff, registered, matched, active, busy 0 (514 ms), retain 7>
| {
|   "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  <class AppleUSBACMData, id 0x100091018, registered, matched, active, busy 0 (0 ms), retain 6>
| {
|   "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  <class IOSerialBSDClient, id 0x100091020, registered, matched, active, busy 0 (0 ms), retain 5>
{
"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"
}

解决方案非常简单。它总是在我的桌子上。您应该订阅以接收有关系统中出现的新kIOSerialBSDServiceValue设备的通知就像这样。此代码也基于Apple USBPrivateDataSample.c

https://developer.apple.com/library/archive/samplecode/USBPrivateDataSample/Introduction/Intro.html#//apple_ref/doc/uid/DTS10000456

CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOSerialBSDServiceValue);
....
// 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
);

当您获得kIOSerialBSDServiceValue(在DeviceAdded()函数中)时,在IOKit树上向上遍历(使用IORegistryEntryGetParentEntry),直到查找您的VID和PID。(请参阅我的第一个有问题的代码片段。)如果您找不到,并且设备树已过,则这不是您的设备。

最新更新