【问题标题】:IOKIT Detecting BSD(unix) name for USB Serial Device with PID and VIDIOKIT 检测带有 PID 和 VID 的 USB 串行设备的 BSD(unix)名称
【发布时间】:2019-07-07 08:50:51
【问题描述】:

我在 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 注册表分支中。 问题是如何使用 IODialinDevice ("/dev/tty.usbmodemMyDeviceName") 属性从由 VID 和 PID 识别的 USB 设备到串行设备 (kIOSerialBSDServiceValue)。

任何帮助表示赞赏!

更新: 这是 ioreg 树:
我可以在我的应用程序中检测到 CDC ACM 数据设备。 (此树中的顶级设备) 在ioreg,我看到了这张照片。所以有孩子,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"
    }

【问题讨论】:

  • 有点相关:stackoverflow.com/q/51908254 你大概可以匹配IOSerialBSDClient 并检查它是否属于你的设备。您也可以尝试从您的设备向下遍历到IOSerialBSDClient,可能使用IORegistryEntryCreateIterator。当您收到设备存在的通知时,IOSerialBSDClient 对象可能不存在。 (我已经很久没有接触过 macOS 了,所以真的帮不上什么忙)
  • 是的,它看起来很相似,但不一样。我从这个问题中获取了父迭代代码。我的问题略有不同。我从父母到孩子。最初我有 USB 设备,我想更深入地了解孩子,了解串行设备。我只是在孩子身上看不到我的串行设备。我最近的想法是我的串行设备不是设备,而是 USB 接口或 USB 端点。可能我需要为我的设备获取 IOUSBInterfaceInterface300 类。但我不确定:-)

标签: macos serial-port usb core-foundation iokit


【解决方案1】:

解决方案非常简单。 它总是在我的桌子上。 您应该订阅以接收有关新的 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。 (请参阅我的第一个代码片段。) 如果您找不到并且设备树已经结束,这不是您的设备。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-28
    • 1970-01-01
    • 1970-01-01
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多