Как однозначно идентифицировать USB-устройство? - PullRequest
4 голосов
/ 01 декабря 2010

Мне было интересно, как получить уникальный идентификатор запоминающего устройства USB.Я уже знаю, как получить серийный идентификатор SCSI из этого поста: Серийный номер USB-накопителя под Linux C ++ В сообщении упоминается использование дескриптора устройства для получения идентификатора.Может кто-нибудь опубликовать код для определения информации дескриптора устройства в Linux?

Ответы [ 7 ]

2 голосов
/ 26 февраля 2011

Я предлагаю использовать libusb . Вы можете найти документацию здесь .

2 голосов
/ 21 февраля 2011

Я делаю это с HAL в C ++ / C, используя QT. Нашел какой-то блог об этом:

Как определить, является ли / dev / * устройством USB

Было бы также возможно сделать это, используя shell & HAL.

2 голосов
/ 01 декабря 2010
ls -l /dev/disk/by-id
1 голос
/ 04 октября 2017

Обобщая ответ Саймона Ригета , я придумал эту функцию bash, которая при наличии необязательного идентификатора поставщика и идентификатора продукта возвращает список имен узлов устройства, связанных с идентификатором этого поставщика и идентификатором этого продукта, если он указан .

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

Итак, если бы я хотел увидеть, какие узлы устройства связаны с идентификатором поставщика 0x1004 и идентификатором продукта 0x6344, я бы сделал следующее:

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

Итак, у нас есть два узла устройства, один из которых имеет класс tty без devtype, а другой - с неизвестным классом, но с devtype usb_device .

Можно также указать только идентификатор поставщика, например:

$ 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 

Если бы я хотел только video4linux класса устройств с идентификатором поставщика 0bda, то я бы сделал следующее:

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

Аргументы в основном фильтруют полный список узлов устройств и связанную с ними информацию. Пропуск одного из этих аргументов или использование пустой строки "" в качестве аргумента отключает фильтр для этого конкретного аргумента.

Аргументы приводятся в следующем порядке: 1: класс, 2: тип, 3: идентификатор поставщика, 4: идентификатор продукта.


Ниже приведена облегченная версия вышеуказанной функции, которая работает быстрее за счет некоторых функций: узлы устройства печатаются без дополнительной информации, и нет фильтра для типа устройства.

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[@]}"
    }
}
1 голос
/ 18 сентября 2015

При использовании USB «имя устройства» устройства может меняться в зависимости от порядка подключения устройства. Удивительно мало устройств имеют реальный серийный номер. Если вы не можете получить уникальную идентификацию от самого устройства, единственным решением будет зависеть от физического адреса подключения. Недостатком этого является то, что адрес меняется, если вы подключаете устройство к другому разъему USB.

Программно вы можете использовать sysfs для получения информации об устройстве, имеющейся в ядре. Sysfs - это представление устройств в файловой системе в том виде, в котором их видит ядро. (Это не настоящие файлы на диске)

С его помощью вы можете: - определить тип устройства с помощью идентификатора продукта и поставщика - прочитать серийный номер устройства, если оно есть. - прочитать номер физического соединения на 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

Этот каталог содержит много информации об устройстве:

idProduct и idVendor могут использоваться для однозначной идентификации типа устройства.

Если существует файл serial , и он содержит уникальный серийный номер, все готово.

В противном случае вы можете использовать физическое соединение в качестве идентификатора, для которого это имя каталога « 4-1.5 ». Оно уникально для физического соединения и, как вы уже упоминали, изменится, если вы подключите устройство на другой порт.

1 голос
/ 21 января 2015

Чтобы добавить к тому, что сказали все остальные:

USB-устройства не всегда имеют серийный номер; даже если кто-то присутствует, он не гарантирован, чтобы быть глобально уникальным. (Например, моя клавиатура Apple USB не имеет серийного номера, а все камеры GoPro имеют один и тот же фиктивный серийный номер 123456789ABC.) Поэтому не всегда можно однозначно идентифицировать устройство. 1006 *

0 голосов
/ 02 апреля 2012

do sudo blkid и в нем будет указан идентификатор всех подключенных устройств с файловой системой

...