IOKIT 使用 PID 和 VID 检测 USB 串行设备的 BSD(unix) 名称
IOKIT Detecting BSD(unix) name for USB Serial Device with PID and VID
我正在 macOS 上使用 USB 串行设备。
如何使用 IOKit 在 macOS 上检测我的 USB 串行设备的 BSD(unix) 名称?
我想获得如下设备名称:"IODialinDevice" = "/dev/tty.usbmodemMyDeviceName"
我的USB设备是USB串口。
我还想检测设备何时连接到机器。
我可以检测到何时连接了带有我的 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 设备,然后我检查 parents VID 和 PID
如果 parent 有 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 的所有 child 个节点。
None 其中包含 IODialinDevice 属性 或 none 其中是 kIOSerialBSDServiceValue 设备。
看来我做错了。
看起来串行设备和 USB 位于不同的 IOKit 注册表分支中。
问题是如何使用 IODialinDevice ("/dev/tty.usbmodemMyDeviceName") 属性 从 VID 和 PID 识别的 USB 设备到串行设备 (kIOSerialBSDServiceValue)。
感谢任何帮助!
更新:
这是 ioreg 树:
我可以在我的应用程序中检测到 CDC ACM 数据设备。 (这棵树中的顶级设备)
在 ioreg 中,我看到了这张图片。所以有 children、AppleUSBACMData 和 IOSerialBSDClient 拥有 IODialinDevice 属性。
但是我无法在我的应用程序中检测到 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
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。 (请参阅我的第一个代码片段。)
如果您找不到并且设备树已结束,则这不是您的设备。
我正在 macOS 上使用 USB 串行设备。
如何使用 IOKit 在 macOS 上检测我的 USB 串行设备的 BSD(unix) 名称? 我想获得如下设备名称:"IODialinDevice" = "/dev/tty.usbmodemMyDeviceName"
我的USB设备是USB串口。 我还想检测设备何时连接到机器。
我可以检测到何时连接了带有我的 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 设备,然后我检查 parents VID 和 PID 如果 parent 有 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 的所有 child 个节点。 None 其中包含 IODialinDevice 属性 或 none 其中是 kIOSerialBSDServiceValue 设备。
看来我做错了。 看起来串行设备和 USB 位于不同的 IOKit 注册表分支中。 问题是如何使用 IODialinDevice ("/dev/tty.usbmodemMyDeviceName") 属性 从 VID 和 PID 识别的 USB 设备到串行设备 (kIOSerialBSDServiceValue)。
感谢任何帮助!
更新:
这是 ioreg 树:
我可以在我的应用程序中检测到 CDC ACM 数据设备。 (这棵树中的顶级设备)
在 ioreg 中,我看到了这张图片。所以有 children、AppleUSBACMData 和 IOSerialBSDClient 拥有 IODialinDevice 属性。
但是我无法在我的应用程序中检测到 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
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。 (请参阅我的第一个代码片段。) 如果您找不到并且设备树已结束,则这不是您的设备。