代码之家  ›  专栏  ›  技术社区  ›  Codo

如何在不迭代IORegistry的情况下创建IOUSBDeviceInterface

  •  0
  • Codo  · 技术社区  · 3 年前

    在一个涉及具有自定义协议的USB设备的项目中,我可以成功地枚举连接的USB设备并使用所需的设备:

    io_iterator_t iter = 0;
    
    // Get the IO registry which has the system information for connected hardware
    io_registry_entry_t entry = IORegistryGetRootEntry(kIOMasterPortDefault);
    if (entry == 0)
        throw usb_error("internal error (failed to get IO registry root entry)", 0);
    
    // Get an iterator for the USB plane
    kern_return_t kret = IORegistryEntryCreateIterator(entry, kIOUSBPlane, kIORegistryIterateRecursively, &iter);
    if (kret != KERN_SUCCESS || iter == 0)
        throw usb_error("internal error (failed to create device iterator)", 0);
    
    // Walk the iterator
    io_service_t service = 0;
    while ((service = IOIteratorNext(iter)) != 0) {
    
        IOUSBDeviceInterface** dev = iokit_helper::get_interface<IOUSBDeviceInterface>(service, kIOUSBDeviceUserClientTypeID, kIOUSBDeviceInterfaceID);
    
        IOObjectRelease(service);
        if (dev == nullptr)
            continue;
        
        ... do something with dev ...
        
        (*dev)->Release(dev);
    }
    
    IOObjectRelease(iter);
    

    由于代码最终将作为Java虚拟机中的JNI库运行,因此我不想保留对 IOUSBDeviceInterface 在很长一段时间内,因为JVM及其垃圾收集将很难确保它们被及时释放。对于大多数USB设备,只有元数据(PID、VID、串行等)是相关的。它们不开放用于交流。所以我宁愿释放 IOUBDeviceInterface 并在实际使用时重新打开。

    有没有办法获得USB设备的设备路径或其他标识符,然后直接创建 IOUBDeviceInterface 而不枚举IO注册表中的所有USB设备?

    或者,如果必须始终使用IO注册表:USB设备的最佳标识符是什么,所以迭代器只返回这一个USB设备?

    0 回复  |  直到 3 年前
        1
  •  1
  •   Codo    3 年前

    提供来自的条目/服务 IOIteratorNext , IORegistryEntryGetPath 做到了:

    io_string_t path;
    int res = IORegistryEntryGetPath(service, kIOServicePlane, path);
    

    它返回的路径如下:

    IOService:/AppleARMPE/arm-io/AppleT600xIO/usb-drd0@2280000/AppleT6000USBXHCI@00000000/usb-drd0-port-hs@00100000/A39F3CD99B172BC@00100000
    

    使用此路径,可以从IO注册表中检索USB设备:

    io_service_t service = IORegistryEntryFromPath(kIOMasterPortDefault, path);
    if (service == MACH_PORT_NULL)
        ...error handling... 
    
    IOUSBDeviceInterface** dev = iokit_helper::get_interface<IOUSBDeviceInterface>(service, kIOUSBDeviceUserClientTypeID, kIOUSBDeviceInterfaceID);
    if (dev == nullptr)
        ...error handling...;
    
    IOReturn ret = (*dev)->USBDeviceOpen(dev);