Linux的/dev/xxx设备节点是自动创建。一般情况下,开发者只能拿到设备号等少数信息。而像一些USB设备,即便是同一个设备,插拔以后可能,生成的/dev/xxx节点名可能也不相同。所以应用编程有时候需要知道,设备节点的具体信息。比如是哪个厂家的USB设备,USB设备的PID和VID是多少,插在了hub的哪个端口上等等.这时候就需要使用libudev获取设备节点的详细信息。

通过libudev获取的USB信息,比较常用的就是PID和VID,

ID_VENDOR_ID 对应的就是USB设备的VID

ID_MODEL_ID 对应的就是USB设备的PID

#include <libudev.h>
#include <stdio.h>
#include <string.h>

/*
* libudev api说明
* https://mirrors.edge.kernel.org/pub/linux/utils/kernel/hotplug/libudev/ch01.html
*/


/**
* 打印/dev/xxx设备节点的properties值
* @devnode: 设备节点文件/dev/xxx,如:/dev/ttyUSB0
*/
int print_devnode_properties(const char *devnode)
{
int ret = 0;
struct udev *udev;
struct udev_device *device;
struct udev_enumerate *enumerate;
struct udev_list_entry *first_entry;
struct udev_list_entry *list_entry;
const char *syspath;

udev = udev_new();
enumerate = udev_enumerate_new(udev);

/*
* 通过枚举器添加匹配条件,如果有多条匹配条件
*/
udev_enumerate_add_match_property(enumerate, "DEVNAME", devnode);

/*
* 根据枚举器设置的条件扫描所有的设备.
* 注意: 如果有多条匹配条件,符合其中一条就会被扫描到,
* 匹配条件越多,扫描越宽松
*/
udev_enumerate_scan_devices(enumerate);

list_entry = udev_enumerate_get_list_entry(enumerate);

if (!list_entry) {
ret = -1;
goto ERROR1;
}

syspath = udev_list_entry_get_name(list_entry);
device = udev_device_new_from_syspath(udev, syspath);

if (!device) {
ret = -1;
goto ERROR1;
}

first_entry = udev_device_get_properties_list_entry(device);

if (!first_entry) {
ret = -1;
goto ERROR2;
}

udev_list_entry_foreach(list_entry, first_entry) {
printf("%s = %s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
}

ERROR2:
udev_device_unref(device);
ERROR1:
udev_enumerate_unref(enumerate);
udev_unref(udev);
return ret;
}


void test_print_devnode_properties(void)
{
print_devnode_properties("/dev/ttyUSB0");
print_devnode_properties("/dev/sda1");
/*
* 异常情况测试
*/
print_devnode_properties("/dev/");
}

/dev/ttyUSB0的打印信息:

DEVLINKS = /dev/serial/by-id/usb-1a86_USB_Serial-if00-port0 /dev/serial/by-path/platform-13500000.otg-usb-0:1.1:1.0-port0
DEVNAME = /dev/ttyUSB0
DEVPATH = /devices/platform/ahb2/13500000.otg/usb1/1-1/1-1.1/1-1.1:1.0/ttyUSB0/tty/ttyUSB0
ID_BUS = usb
ID_MODEL = USB_Serial
ID_MODEL_ENC = USB\x20Serial
ID_MODEL_FROM_DATABASE = HL-340 USB-Serial adapter
ID_MODEL_ID = 7523
ID_PATH = platform-13500000.otg-usb-0:1.1:1.0
ID_PATH_TAG = platform-13500000_otg-usb-0_1_1_1_0
ID_REVISION = 0264
ID_SERIAL = 1a86_USB_Serial
ID_TYPE = generic
ID_USB_CLASS_FROM_DATABASE = Vendor Specific Class
ID_USB_DRIVER = ch341
ID_USB_INTERFACES = :ff0102:
ID_USB_INTERFACE_NUM = 00
ID_VENDOR = 1a86
ID_VENDOR_ENC = 1a86
ID_VENDOR_FROM_DATABASE = QinHeng Electronics
ID_VENDOR_ID = 1a86
MAJOR = 188
MINOR = 0
SUBSYSTEM = tty
USEC_INITIALIZED = 4234570131

/dev/sda1的打印信息:

DEVLINKS = /dev/disk/by-id/usb-Mass_Storage_Device_121220160204-0:0-part1 /dev/disk/by-label/HHP /dev/disk/by-partuuid/e7c35f5b-01 /dev/disk/by-path/platform-13500000.otg-usb-0:1.2:1.0-scsi-0:0:0:0-part1 /dev/disk/by-uuid/AECB-FA14
DEVNAME = /dev/sda1
DEVPATH = /devices/platform/ahb2/13500000.otg/usb1/1-1/1-1.2/1-1.2:1.0/host7/target7:0:0/7:0:0:0/block/sda/sda1
DEVTYPE = partition
ID_BUS = usb
ID_FS_LABEL = HHP
ID_FS_LABEL_ENC = HHP
ID_FS_TYPE = vfat
ID_FS_USAGE = filesystem
ID_FS_UUID = AECB-FA14
ID_FS_UUID_ENC = AECB-FA14
ID_FS_VERSION = FAT32
ID_INSTANCE = 0:0
ID_MODEL = Storage_Device
ID_MODEL_ENC = Storage\x20Device\x20\x20
ID_MODEL_ID = 1212
ID_PART_ENTRY_DISK = 8:0
ID_PART_ENTRY_NUMBER = 1
ID_PART_ENTRY_OFFSET = 2048
ID_PART_ENTRY_SCHEME = dos
ID_PART_ENTRY_SIZE = 30879744
ID_PART_ENTRY_TYPE = 0xc
ID_PART_ENTRY_UUID = e7c35f5b-01
ID_PART_TABLE_TYPE = dos
ID_PART_TABLE_UUID = e7c35f5b
ID_PATH = platform-13500000.otg-usb-0:1.2:1.0-scsi-0:0:0:0
ID_PATH_TAG = platform-13500000_otg-usb-0_1_2_1_0-scsi-0_0_0_0
ID_REVISION = 1.00
ID_SERIAL = Mass_Storage_Device_121220160204-0:0
ID_SERIAL_SHORT = 121220160204
ID_TYPE = disk
ID_USB_DRIVER = usb-storage
ID_USB_INTERFACES = :080650:
ID_USB_INTERFACE_NUM = 00
ID_VENDOR = Mass
ID_VENDOR_ENC = Mass\x20\x20\x20\x20
ID_VENDOR_ID = 14cd
MAJOR = 8
MINOR = 1
SUBSYSTEM = block
USEC_INITIALIZED = 4238784457