How do I uniquely identify a USB device?

I was wondering how to get the unique identifier of a USB storage device. I already know how to get the SCSI serial identifier from this message: the serial number of the USB drive under Linux C ++. The message mentions the use of a device descriptor to get the identifier. Can someone post code to determine device descriptor information in Linux?

+4
source share
7 answers
ls -l /dev/disk/by-id 
+2
source

I am doing this with a HAL in C ++ / C using QT. Found a blog about it:

How to determine if / dev / * is a USB device

You can also do this using shell and HAL.

+2
source

I suggest using libusb . Here you can find the documentation here .

+2
source

To add to the above all the others:

USB devices do not always have a serial number; even if present, it is not guaranteed to be globally unique. (For example, my Apple USB keyboard does not have a serial number, and GoPro cameras have the same dummy serial number 123456789ABC .) Thus, it is not always possible to uniquely identify a device.

+1
source

With a USB device, the “device name” of the device may change, depending on the order in which it is connected. Surprisingly few devices have a real serial number. If you cannot get a unique identifier from the device itself, the only solution will be to determine the physical address of the connection. The disadvantage of this is that the address changes if you connect the device to another USB port.

Programmatically, you can use sysfs to get kernel information related to a device. Sysfs is a file system representation of devices that the kernel sees. (Its not real files on disk)

With it, you can: - determine the type of device with the identifier of the product and the supplier - read the serial number of the device, if any. - read the physical connection number on the USB hub

You can start by looking for your device type in / sys / class. In this example, I am using the USB → LPT port. But the principle is the same.

 $ 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 

Remove the device name from the uevent file:

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

add / dev so that you open the device name: / dev / usb / lp1

Use the real path: $ cd -P / sys / class / usbmisc / lp1

Step back 3 branches:

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

This directory contains a lot of information about the device:

idProduct and idVendor can be used to uniquely identify the type of device.

If there is a serial file and it contains a unique serial number, you are done.

Otherwise, you can use the physical connection as the identifier, which is the name of this directory " 4-1.5 ". It is unique to the physical connection and will, as you said, change if you connect the device to another port.

+1
source

Summarizing the Simon Rigét answer , I came up with this bash function, which, given the optional vendor identifier and product identifier, returns a list of node device names associated with this vendor identifier and product identifier, if one is specified.

 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 } 

For example, this is what my lususb says:

 $ 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 

So, if I wanted to see which device nodes are associated with the vendor identifier 0x1004 and product identifier 0x6344, I would do the following:

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

So, we have two device nodes, one of which has a tty class without devtype, and the other an unknown class, but with devtype usb_device.

You can also specify a vendor identifier, for example:

 $ 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 

If I only need devices of the video4linux class whose seller ID is 0bda, I would do the following:

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

Arguments are basically filters over the entire list of device nodes and their associated information. Omitting one of these arguments or using the empty string "" as an argument disables the filter for this particular argument.

The arguments are given in the following order: 1: class, 2: type, 3: vendor identifier, 4: product identifier.


Here is an example of a lightweight version of the above function, which runs faster due to some functions: the device nodes are printed without additional information, and there is no filter for the device type.

 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
source

do sudo blkid and it will display the identifier of all connected devices with the file system

0
source

All Articles