如何使用libudev通过PID和VID获取设备的/dev路径
解答
- 该需求完全可实现。
- 你当前无法获取目标
/dev路径的核心原因:你枚举的是usb子系统下类型为usb_device的USB总线原生设备节点,这类节点对应的设备路径是/dev/bus/usb/xxx/xxx格式的总线访问路径,不是USB设备绑定功能驱动后生成的ttyUSB、hidraw这类功能设备节点,自然拿不到你要的串口路径。
实现方法
你可以任选以下两种方式实现:
方法1:在现有匹配逻辑基础上遍历子设备找功能节点
找到匹配VID/PID的USB设备对象后,遍历它的所有子设备,筛选对应功能子系统的节点,调用接口取dev路径即可。以USB转串口设备(对应tty子系统,生成ttyUSBx/ttyACMx节点)为例,在你代码的匹配判断分支中添加如下逻辑:
if (vendor_id == VID && product_id == PID) { struct udev_device *child = nullptr; const char* target_path = nullptr; // 遍历当前USB设备的所有子设备 udev_device_foreach_child(child, raw_dev) { const char *subsys = udev_device_get_subsystem(child); // 匹配tty子系统,若你用的是HID/存储类设备,替换为对应子系统名即可 if (subsys && strcmp(subsys, "tty") == 0) { target_path = udev_device_get_devnode(child); break; } } // target_path即为目标路径,例如/dev/ttyUSB0 if (target_path) { printf("Found target device: %s\n", target_path); } }
注意:如果你的设备不是串口类设备,需要将子系统匹配规则替换为对应类型:比如HID设备匹配
hidraw子系统拿到/dev/hidrawx路径,USB存储设备匹配block子系统拿到/dev/sdx路径。
方法2:直接枚举目标功能子系统匹配PID/VID
这种方式代码更简洁,不需要遍历子设备:直接枚举你需要的功能子系统(比如tty)的设备,这类设备会自动继承父USB设备的idVendor、idProduct属性,匹配成功后直接取devnode即可:
ud = udev_new(); struct udev_enumerate *enumerate = udev_enumerate_new(ud); // 直接匹配tty子系统,不需要匹配usb子系统和usb_device类型 udev_enumerate_add_match_subsystem(enumerate, "tty"); udev_enumerate_scan_devices(enumerate); struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate); struct udev_list_entry *dev_list_entry; udev_list_entry_foreach(dev_list_entry, devices) { const char *sysfs_path = udev_list_entry_get_name(dev_list_entry); struct udev_device *dev = udev_device_new_from_syspath(ud, sysfs_path); uint16_t vendor_id; uint16_t product_id; // 直接从tty设备读取继承的VID/PID属性,判断读取返回值避免无效值 if (udev_get_sysattr_u16_base16(dev, "idVendor", &vendor_id) == 0 && udev_get_sysattr_u16_base16(dev, "idProduct", &product_id) == 0 && vendor_id == VID && product_id == PID) { // 直接获取dev路径,不需要遍历子设备 const char* target_path = udev_device_get_devnode(dev); printf("Found target device: %s\n", target_path); } udev_device_unref(dev); } // 用完后释放udev对象,避免内存泄漏 udev_enumerate_unref(enumerate); udev_unref(ud);
其他注意事项
- 所有
udev_*创建的对象用完后必须调用对应的_unref接口释放,避免内存泄漏。 - 如果设备存在多个接口对应多个功能节点(比如USB转多串口设备),遍历子设备时会拿到多个
/dev/ttyUSBx路径,可根据接口号、驱动名等属性进一步筛选你需要的节点。
内容的提问来源于stack exchange,提问作者dan123123
相关产品推荐
相关产品推荐

