command to determine ports of a device (like /dev/ttyUSB0)
I have a question regarding the ports in Linux. If I connect my device via USB and want to check its port I can’t do it using the command lsusb, which only specifies bus number and device number on this bus:
[ziga@Ziga-PC ~]$ lsusb Bus 003 Device 007: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
Is there a command that tells me the port the device is connected to directly? Only way to do this until now was to disconect and reconnect and using the command:
[ziga@Ziga-PC ~]$ dmesg | grep tty [ 0.000000] console [tty0] enabled [ 0.929510] 00:09: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A [ 4.378109] systemd[1]: Starting system-getty.slice. [ 4.378543] systemd[1]: Created slice system-getty.slice. [ 8.786474] usb 3-4.4: FTDI USB Serial Device converter now attached to ttyUSB0
What are you trying to accomplish? Do you want to associate a device in /dev with an entry in lsusb ? Or do you want to list all devices in /dev that are derived from a physical USB device? Or are you just wanting ls /dev/ttyUSB* ?
I just need a command which will give me port of a device and will not push me to disconnect and reconnect my devices. ls /dev/ttyUSB* will only list maybee 10 ports but from this list I cannot tell which one is for my device.
I use this Python 3 script all the time, it works perfectly well on Linux, macOS and Raspberry Pi OS: gist.github.com/NicHub/d86d34f2292da017ac20ca1e6a7cb76d
7 Answers 7
I’m not quite certain what you’re asking. You mention ‘port’ several times, but then in your example, you say the answer is /dev/ttyUSB0 , which is a device dev path, not a port. So this answer is about finding the dev path for each device.
Below is a quick and dirty script which walks through devices in /sys looking for USB devices with a ID_SERIAL attribute. Typically only real USB devices will have this attribute, and so we can filter with it. If we don’t, you’ll see a lot of things in the list that aren’t physical devices.
#!/bin/bash for sysdevpath in $(find /sys/bus/usb/devices/usb*/ -name dev); do ( syspath="$" devname="$(udevadm info -q name -p $syspath)" [[ "$devname" == "bus/"* ]] && exit eval "$(udevadm info -q property --export -p $syspath)" [[ -z "$ID_SERIAL" ]] && exit echo "/dev/$devname - $ID_SERIAL" ) done
On my system, this results in the following:
/dev/ttyACM0 - LG_Electronics_Inc._LGE_Android_Phone_VS930_4G-991c470 /dev/sdb - Lexar_USB_Flash_Drive_AA26MYU15PJ5QFCL-0:0 /dev/sdb1 - Lexar_USB_Flash_Drive_AA26MYU15PJ5QFCL-0:0 /dev/input/event5 - Logitech_USB_Receiver /dev/input/mouse1 - Logitech_USB_Receiver /dev/input/event2 - Razer_Razer_Diamondback_3G /dev/input/mouse0 - Razer_Razer_Diamondback_3G /dev/input/event3 - Logitech_HID_compliant_keyboard /dev/input/event4 - Logitech_HID_compliant_keyboard
Explanation:
find /sys/bus/usb/devices/usb*/ -name dev
Devices which show up in /dev have a dev file in their /sys directory. So we search for directories matching this criteria.
We want the directory path, so we strip off /dev .
devname="$(udevadm info -q name -p $syspath)"
This gives us the path in /dev that corresponds to this /sys device.
This filters out things which aren’t actual devices. Otherwise you’ll get things like USB controllers & hubs. The exit exits the subshell, which flows to the next iteration of the loop.
eval "$(udevadm info -q property --export -p $syspath)"
The udevadm info -q property —export command lists all the device properties in a format that can be parsed by the shell into variables. So we simply call eval on this. This is also the reason why we wrap the code in the parenthesis, so that we use a subshell, and the variables get wiped on each loop.
More filtering of things that aren’t actual devices.
echo "/dev/$devname - $ID_SERIAL"
I hope you know what this line does 🙂
Thank you. I will learn a lot from your anwser and now I see that terms werent completely clear to me. Is there any shorter way? Maybee a command already integrated in the Linux itself?
@Walf Yes, that is the purpose. The eval creates unknown variables that differ per device. Without () , when it checks $ID_SERIAL , it could be from a previous device.
You can use this command to explore your device if connected to usb0 :
udevadm info -a -p $(udevadm info -q path -n /dev/ttyUSB0)
Assuming that you know what the device you plugged in is, in 14.04 Ubuntu, at least, there is the command usb-devices that you can look through and find the information:
$ usb-devices T: Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=480 MxCh= 3 D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1d6b ProdID=0002 Rev=04.04 S: Manufacturer=Linux 4.4.0-131-generic ehci_hcd S: Product=EHCI Host Controller S: SerialNumber=0000:00:1a.0 C: #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=0mA I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
And the first line lists bus and port, as well as the device number that lsusb gives.
To be fair, as the top answer notes, the question isn’t clear on whether it’s asking for «how do I derive the port» vs «how do I get the exact path?».
I found @phemmer’s accepted answer regularly helpful and turned it into a bash script. I added shell process backgrounding to make it run a bit faster for lots of USB devices connected to a system (which when this is most useful).
#!/bin/bash #findusbdev.sh if [[ "$1" =~ ^(-h|--help)$ ]]; then echo "Find which USB devices are associated with which /dev/ nodes Usage: $0 [-h|--help] [searchString] -h | --help Prints this message searchString Print only /dev/ of matching output With no arguments $0 prints information for all possible USB device nodes E.g. $0 \"FTDI_FT232\" - will show /dev/ttyUSBX for a device using the FTDI FT232 chipset. " exit 0 fi devs=$( ( for sysdevpath in $(find /sys/bus/usb/devices/usb*/ -name dev ); do # ( to launch a subshell here ( syspath="$" devname="$(udevadm info -q name -p $syspath)" [[ "$devname" == "bus/"* ]] && exit eval "$(udevadm info -q property --export -p $syspath)" [[ -z "$ID_SERIAL" ]] && exit echo "/dev/$devname - $ID_SERIAL" )& # & here is causing all of these queries to run simultaneously done # wait then gives a chance for all of the iterations to complete wait # output order is random due to multiprocessing so sort results ) | sort ) if [ -z "$1" ]; then echo "$" else echo "$" | grep "$1" | awk '' fi
$ ./findusbdev.sh /dev/input/event15 - Peppercon_AG_Multidevice_E999EC989B0BAFB78F9F225288EC6B0A /dev/input/event16 - Peppercon_AG_Multidevice_E999EC989B0BAFB78F9F225288EC6B0A /dev/input/mouse0 - Peppercon_AG_Multidevice_E999EC989B0BAFB78F9F225288EC6B0A /dev/ttyUSB0 - FTDI_FT230X_Basic_UART_D308B2AI /dev/ttyUSB1 - FTDI_FT232R_USB_UART_AH07DPSR
$ ./findusbdev.sh FT230X /dev/ttyUSB0
$ ./findusbdev.sh -h Find which USB devices are associated with which /dev/ nodes Usage: ./findusbdev.sh [-h|--help] [searchString] -h | --help Prints this message searchString Print only /dev/ of matching output With no arguments ./findusbdev.sh prints information for all possible USB device nodes E.g. ./findusbdev.sh "FTDI_FT232" - will show /dev/ttyUSBX for a device using the FTDI FT232 chipset.
Embedded Linux USB device detect port and address
I’m developing a USB application for my board. It has two USB ports. When I plug in a USB drive in each of them I get the following messages on console : On port 1 :
usb 1-1: new high speed USB device using atmel-ehci and address 4 usb 1-1: New USB device found, idVendor=0781, idProduct=5567 usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 usb 1-1: Product: Cruzer Blade usb 1-1: Manufacturer: SanDisk usb 1-1: SerialNumber: 3515430A2EE2729D scsi2 : usb-storage 1-1:1.0 scsi 2:0:0:0: Direct-Access SanDisk Cruzer Blade 8.02 PQ: 0 ANSI: 0 CCS sd 2:0:0:0: [sdb] 7856127 512-byte logical blocks: (4.02 GB/3.74 GiB) sd 2:0:0:0: [sdb] Write Protect is off sd 2:0:0:0: [sdb] Assuming drive cache: write through sd 2:0:0:0: [sdb] Assuming drive cache: write through sdb: sdb1 sd 2:0:0:0: [sdb] Assuming drive cache: write through sd 2:0:0:0: [sdb] Attached SCSI removable disk
usb 1-2: USB disconnect, address 3 usb 1-2: new high speed USB device using atmel-ehci and address 5 usb 1-2: New USB device found, idVendor=0781, idProduct=5567 usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 usb 1-2: Product: Cruzer Blade usb 1-2: Manufacturer: SanDisk usb 1-2: SerialNumber: 3515430A2EE2729D scsi3 : usb-storage 1-2:1.0 scsi 3:0:0:0: Direct-Access SanDisk Cruzer Blade 8.02 PQ: 0 ANSI: 0 CCS sd 3:0:0:0: [sda] 7856127 512-byte logical blocks: (4.02 GB/3.74 GiB) sd 3:0:0:0: [sda] Write Protect is off sd 3:0:0:0: [sda] Assuming drive cache: write through sd 3:0:0:0: [sda] Assuming drive cache: write through sda: sda1 sd 3:0:0:0: [sda] Assuming drive cache: write through sd 3:0:0:0: [sda] Attached SCSI removable disk
But these messages are on the console. I want to detect which device has been connected to which port with the address (like sda, sdb, etc.) I have google a bit on this and found two system paths that give this info independently : 1) /sys/bus/usb/devices/1-x 2) /sys/class/scsi_disk/x:0:0:0/device The first one gives this info :
1-2:1.0 bus maxchild authorized busnum product bConfigurationValue configuration quirks bDeviceClass descriptors remove bDeviceProtocol dev serial bDeviceSubClass devnum speed bMaxPacketSize0 devpath subsystem bMaxPower driver uevent bNumConfigurations ep_00 urbnum bNumInterfaces idProduct usb_device:usbdev1.4 bcdDevice idVendor version bmAttributes manufacturer
block:sdb iorequest_cnt scsi_disk:2:0:0:0 bus max_sectors scsi_level delete modalias state device_blocked model subsystem driver queue_depth timeout evt_media_change queue_type type iocounterbits rescan uevent iodone_cnt rev vendor ioerr_cnt scsi_device:2:0:0:0
So there is no common info between these two datastructures. I can get the port no. and serial no. of the USB device from the first path. And I can get the address (sda, sdb, etc.) from the second path. But there is no common info between them. How can I know that a particular USB device on port 1 is mounted on sda ? Or a device on port 2 if mounted on sdc ??