5

我想知道如何获取 USB 存储设备的唯一 ID。我已经知道如何从这篇文章中获取 SCSI 序列号:Linux C++ 下的 USB 驱动器序列号 该文章提到使用设备描述符获取 ID。有人可以发布一些代码来确定Linux下的设备描述符信息吗?

4

6 回答 6

2
ls -l /dev/disk/by-id
于 2010-12-01T17:21:12.337 回答
2

我建议使用libusb您可以在此处找到文档。

于 2011-02-25T23:20:07.120 回答
1

添加到其他人所说的话:

USB 设备并不总是有序列号;即使存在一个,也不能保证它是全球唯一的。(例如,我的 Apple USB 键盘没有序列号,而GoPro 相机都有相同的伪造序列号123456789ABC。)因此,并非总是可以唯一识别设备。

于 2015-01-20T22:06:39.350 回答
1

使用 USB,设备的“设备名称”可以更改,具体取决于设备连接的顺序。令人惊讶的是,很少有设备具有真实的序列号。如果您无法从设备本身获得唯一标识,唯一的解决方案是依赖连接的物理地址。这样做的缺点是,如果您将设备插入另一个 USB 连接器,地址会发生变化。

以编程方式,您可以使用 sysfs 获取内核拥有的有关设备的信息。Sysfs 是内核看到的设备的类似文件系统的表示。(它不是磁盘上的真实文件)

有了它,您可以: - 使用产品和供应商 ID 识别设备类型 - 读取设备的序列号(如果有)。- 读取 USB 集线器上的物理连接号

您可以从在 /sys/class 中查找您的设备类型开始。在本例中,我使用 USB→LPT 端口。但原理是一样的。

$ ls -l /sys/class/usbmisc
lp1 -> ../../devices/pci0000:00/0000:00:1d.0/usb4/4-1/4-1.5/4-1.5:1.0/usbmisc/lp1
lp2 -> ../../devices/pci0000:00/0000:00:1d.0/usb4/4-1/4-1.6/4-1.6:1.0/usbmisc/lp2

从 uevent 文件中获取设备名称:

cat /sys/class/usbmisc/lp1/uevent
MAJOR=180
MINOR=1
DEVNAME=__usb/lp1__

添加 /dev 以便获得要打开的设备名称:/dev/usb/lp1

使用真实路径: $ cd -P /sys/class/usbmisc/lp1

后退 3 个分支:

$ cd ../../../
/sys/devices/pci0000:00/0000:00:1d.0/usb4/4-1/4-1.5

这个目录包含很多关于设备的信息:

idProductidVendor可用于唯一标识设备类型。

如果有一个序列文件并且它包含一个唯一的序列号,那么您就完成了。

否则,您的选择是使用物理连接作为标识,即此目录名称“<strong>4-1.5” 它对于物理连接是唯一的,并且正如您已经提到的,如果您将设备插入另一个端口,它会发生变化。

于 2015-09-17T21:25:00.800 回答
1

概括 Simon Rigét 的回答,我想出了这个 bash 函数,给定可选的供应商 ID 和产品 ID,返回设备节点名称列表,如果给定,则与该供应商 ID 和该产品 ID 相关。

getDevNodes() {
    if [ -n "$1" ] && [ "$1" != "no_class" ]; then
        2>/dev/null find -L /sys/class/$1 -maxdepth 2 -mindepth 2 -name uevent -exec realpath "{}" +
    else
        find /sys/devices -name uevent
    fi | {        
        if [ -z "$1" ]; then
            readarray -t lines < <(find /sys/class -maxdepth 2 -mindepth 2 -type l -print -exec realpath "{}" +)

            local -i count=${#lines[@]} sys_dev=count/2 sys_class=0
            local -A classes

            while [ $sys_dev -lt $count ]; do
                    class="${lines[$sys_class]#/*/*/}"
                    class="${class%/*}"
                    classes["${lines[$sys_dev]}"]="$class"

                    sys_dev+=1
                    sys_class+=1                    
            done
        fi

        readarray -t uevents

        for u in "${uevents[@]}"; do       
            DEVNAME=; DEVTYPE=no_type; while IFS="=" read key value; do {
                [ "$key" = "DEVNAME" ] && DEVNAME=/dev/"$value" 
            } || {
                [ "$key" = "DEVTYPE" ] && DEVTYPE="$value"                 
            }; done < "$u"

            if [ -n "$DEVNAME" ]; then              
                path="${u%/uevent}"
                while [ "$path" != "/sys/devices" ] && ! [ -f "$path"/idVendor ]; do
                    path="${path%/*}"
                done

                [ "$path" != "/sys/devices" ] && {
                    read readIdVendor < "$path"/idVendor
                    read readIdProduct < "$path"/idProduct
                } || {
                    readIdVendor=----
                    readIdProduct=----
                }

                echo "${1:-${classes[${u%/uevent}]:-no_class}}" "$DEVTYPE" "$readIdVendor" "$readIdProduct" "$DEVNAME" 
            fi
        done
    } | grep "^${1:-[[:graph:]]\+} ${2:-[[:graph:]]\+} ${3:-....} ${4:-....}" | cat
}

例如,这是我的 lsusb 告诉我的:

$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 008: ID 0bda:b719 Realtek Semiconductor Corp. 
Bus 001 Device 006: ID 0bda:57b5 Realtek Semiconductor Corp. 
Bus 001 Device 004: ID 0bda:0129 Realtek Semiconductor Corp. RTS5129 Card Reader Controller
Bus 001 Device 097: ID 1004:6344 LG Electronics, Inc. G2 Android Phone [tethering mode]
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

因此,如果我想查看哪些设备节点与供应商 id 0x1004 和产品 id 0x6344 相关联,我会执行以下操作:

$ getDevNodes "" "" 1004 6344
no_class        usb_device      1004 6344 /dev/bus/usb/001/097 
tty             no_type         1004 6344 /dev/ttyACM0 

所以我们有两个设备节点,其中一个是没有 devtype 的tty 类,另一个是未知类但有一个 devtype usb_device

也可以只提供供应商 ID,如下所示:

$ getDevNodes "" "" 0bda 
no_class        usb_device      0bda 0129 /dev/bus/usb/001/004 
no_class        usb_device      0bda b719 /dev/bus/usb/001/008 
no_class        no_type         0bda 57b5 /dev/media0 
video4linux     no_type         0bda 57b5 /dev/video0 
input           no_type         0bda 57b5 /dev/input/event14 
no_class        usb_device      0bda 57b5 /dev/bus/usb/001/006 

如果我只想要供应商 id 为 0bda 的video4linux 类设备,那么我将执行以下操作:

$ getDevNodes video4linux "" "" 0bda
video4linux     no_type         0bda 57b5 /dev/video0 

参数基本上是对设备节点及其相关信息的完整列表的过滤器。省略其中一个参数,或使用空字符串""作为参数,将禁用该特定参数的过滤器。

参数按以下顺序给出:1:类,2:类型,3:供应商 ID,4:产品 ID。


下面是上述函数的精简版,它以牺牲某些功能为代价运行得更快:打印设备节点时没有附加信息,并且没有针对设备类型的过滤器。

getDevNodesLite() {
    if [ -n "$1" ]; then
        2>/dev/null find -L /sys/class/$1 -maxdepth 2 -mindepth 2 -name uevent -exec realpath "{}" +
    else
        find /sys/devices -name uevent
    fi | {
        if [ -n "$2" ]; then
            readarray -t uevents              

            for u in "${uevents[@]}"; do
                path="${u%/uevent}"
                while [ "$path" != "/sys/devices" ] && ! [ -f "$path"/idVendor ]; do
                    path="${path%/*}"
                done

                [ "$path" != "/sys/devices" ] && read readValue < "$path"/idVendor && [ "$readValue" = "$2" ] && {
                    if [ -n "$idProduct" ]; then
                        read readValue < "$path"/idProduct && [ "$readValue" = "$3" ]
                    fi
                } && echo "$u"
            done
        else
            cat
        fi
    } | {
        readarray -t uevents              

        [ ${#uevents[@]} -gt 0 ] && sed -n 's,DEVNAME=\(.*\),/dev/\1,p' "${uevents[@]}"
    }
}
于 2017-10-04T09:16:30.120 回答
0

这样做sudo blkid,它将列出所有具有文件系统的已安装设备的 ID

于 2012-04-02T11:32:59.367 回答