获取挂载到/dev文件夹的USB设备的唯一序列号

9

我将2个网络摄像头连接到计算机上,并在/dev目录中列出了以下摄像头:/dev/video0; /dev/video1。

您能否帮助我编写C代码获取摄像头的序列号,输入为:/dev/video[0;1]


1
学习lsusb的源代码或者使用strace追踪它。它正在读取/sys/bus/usb/devices下的一些文件。 - Basile Starynkevitch
尝试使用 sdparm -i /dev/video0 命令来查看是否能帮助您。 - Estatistics
5个回答

25

我也遇到了同样的问题,找到解决方案花费了一些时间。任何以“只需使用lsusb”开始的解决方案都是不正确的。你可以找到设备的序列号,但是它提供的额外信息都不能帮助你确定它链接到哪个/dev/video。

解决方案:

/bin/udevadm info --name=/dev/video1 | grep SERIAL_SHORT

输出:

E: ID_SERIAL_SHORT=256DEC57

在我的设置中,我发现有两个具有相同ID_SERIAL_SHORT的设备,因此这并不完全正确。 - debuti
1
@debuti,这个问题是因为你的USB设备。它们使用了相同的序列号或者没有序列号的能力,导致出现了相同的序列号。你可以通过重新配置硬件的序列号来解决这个问题。例如,如果你正在使用CP2102 USB转UART,你可以使用CP210xSetIDs.exe。 - SuB
请参阅此处有关 USB 设备的唯一标识符的更多信息:https://dev59.com/YmYq5IYBdhLWcg3w-FTQ#14055578。 - SuB

9

根据使用udevadm的提示和http://www.signal11.us/oss/udev/的教程,我得到了下面的代码来获取我的网络摄像头的串行信息。

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

int main(int argc, char **argv)
{
  struct udev *udev;
  struct udev_device *dev;
  struct udev_enumerate *enumerate;
  struct udev_list_entry *list, *node;
  const char *path;

  udev = udev_new();
  if (!udev) {
    printf("can not create udev");
    return 0;
  }

  enumerate = udev_enumerate_new(udev);
  udev_enumerate_add_match_subsystem(enumerate, "video4linux");
  udev_enumerate_scan_devices(enumerate);

  list = udev_enumerate_get_list_entry(enumerate);
  udev_list_entry_foreach(node, list) {
    path = udev_list_entry_get_name(node);
    dev = udev_device_new_from_syspath(udev, path);

    printf("Printing serial for %s\n", path);
    printf("ID_SERIAL=%s\n",
        udev_device_get_property_value(dev, "ID_SERIAL"));
    printf("ID_SERIAL_SHORT=%s\n",
        udev_device_get_property_value(dev, "ID_SERIAL_SHORT"));

    udev_device_unref(dev);
  }
  return 0;
}

3

您可以使用lsusb命令,但需要添加详细标志并确保使用sudo,否则串行号将不正确。

sudo lsusb -v

如果上述内容过于冗长,可以运行lsusb命令获取设备ID:
$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 012: ID 1ab1:0e11 Rigol Technologies
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

然后使用设备标志运行lsusb并使用grep命令查找序列号。

因此,对于Rigol设备的序列号:

$ sudo lsusb -s 012 -v|grep -i iserial
  iSerial                 3 DP8C221100000

1
谢谢!我认为这个回复值得更多的关注,因为它(即带有详细标志的lsusb命令)很可能是许多来到这里的人正在寻找的 :) - datalowe

1
通过对libusb的尝试,发现有一个标准的 getSerialNumber() 方法。不幸的是,并非所有USB设备都实现了这个方法。我有一些便宜的 $4 网络摄像头返回的内容为 None。这些接口会公开其他元数据,比如 VendorID 和 ProductID,我看到一些代码试图使用它们作为唯一标识符,但不能保证其唯一性,特别是如果您有多个相同型号的设备。
但是,假设您已获取了设备的序列号,下一个问题是找出它对应哪个 /dev/videoN 文件。由于我安装了旧版本的 libusb,所以无法让返回USB设备完整 sysfs 路径的方法正常工作,因此我从 hwinfo 的输出中提取了所有与摄像头相关的块,然后从中提取了看起来像以下内容的部分:
SysFS BusID: 1-1.2:1.0

USB设备实际上形成了一个复杂的树形结构,而BusID编码就表示该设备在该树中的位置。

然后,您可以使用该BusID查找设备在文件系统中的位置以及视频路径,应该位于:

/sys/bus/usb/devices/<BusID>/video4linux/

那是一个目录,在里面你会找到一个与 /dev 中的 videoN 文件匹配的文件。

-1

查看lsusb命令,你会发现它使用libusb,它有许多功能,特别是用于USB设备处理和枚举libudev也可能相关。

或者,可以使用popen命令执行lsusb...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接