Map physical USB device path to the Bus/Device number returned by lsusb

17,065

Solution 1

Firstly, we need to prepend /sys to the path returned by udev, so that path becomes something like: /sys/devices/pci0000:00/0000:00:1d.0/usb5/5-2. Then go to this directory, and there will be several files in it. Among others, there are busnum and devnum files, they contain these "logical" numbers. So, in bash script, we can retrieve them like that:

devpath='/devices/pci0000:00/0000:00:1d.0/usb5/5-2'

busnum=$(cat "/sys/$devpath/busnum")
devnum=$(cat "/sys/$devpath/devnum")

# we might want to make busnum and devnum have leading zeros
# (say, "003" instead of "3", and "012" instead of "12")
busnum=$(printf %03d $busnum)
devnum=$(printf %03d $devnum)

# now, we can retrieve device data by   lsusb -D /dev/bus/usb/$busnum/$devnum

echo "busnum=$busnum, devnum=$devnum"

Also note that udev can return these busnum and devnum directly: in RUN+="..." we can use substitutions $attr{busnum} and $attr{devnum} respectively.

Solution 2

The accepted answer really didn't help me that much. I finally found out a way by probing the idProduct and idVendor if they exist. Here's a shell script

#!/bin/bash
{ 
  cd /sys/bus/usb/devices
  for i in *; do 
    [ -e $i/idProduct ] && echo $(cat $i/idVendor $i/idProduct) $i
  done
}

Here's what I get on my system.

$ ./script
0424 2514 1-3
8087 0024 2-1
0a5c 21e6 2-1.4
8087 0024 4-1
1d6b 0002 usb1
1d6b 0002 usb2
1d6b 0003 usb3
1d6b 0002 usb4

$ lsusb
Bus 004 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 004 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 006: ID 0a5c:21e6 Broadcom Corp. BCM20702 Bluetooth 4.0 [ThinkPad]
Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Here I can see, that for instance 0a5c:21e6, which is a bluetooth device, maps to 2-1.4.

For even greater convenience you could define this as a function in your shell, something like

$ cat >> ~/.bashrc << ENDL
gousb() {
  for i in /sys/bus/usb/devices/*; do 
    if [ -e \$i/idProduct ]; then
      if [ \$(cat \$i/idVendor):\$(cat \$i/idProduct) = \$1 ]; then 
        cd \$i
        return
      fi
    fi
  done

  echo "\$1 not found :-("
}
ENDL
$ source ~/.bashrc
$ gousb 0a5c:21e6
$ pwd 
/sys/bus/usb/devices/2-1.4
Share:
17,065

Related videos on Youtube

Dmitry Frank
Author by

Dmitry Frank

I'm a passionate software engineer with strong background in low-level parts (MCU real-time kernels, C, Assembler), and experienced in higher-level technologies as well: Go, C++, JavaScript, and many others. Author of the well-formed and carefully tested real-time kernel for 16- and 32-bit MCUs: TNeo, which is now used by several companies. One of my hobby projects is a geeky bookmarking service written in Go and PostgreSQL: Geekmarks. Some of my articles: How I ended up writing a new real-time kernel How do JavaScript closures work under the hood Unit-testing (embedded) C applications with Ceedling Object-oriented techniques in C See more at dmitryfrank.com

Updated on September 18, 2022

Comments

  • Dmitry Frank
    Dmitry Frank over 1 year

    I need to get the title of the attached USB device. I can do that with lsusb.

    udev allows some substitutions when I write rules: say, we can use $kernel to get name of the device, or $devpath to get path to the device.

    But problem is that lsusb returns string like that:

    Bus 005 Device 032: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
    

    But udev's devpath is:

    /devices/pci0000:00/0000:00:1d.0/usb5/5-2 
    

    Bus number is the same (5), but numbers are different: Device 032 seems to be some logical number (when I reattach the device, this number increases), and 2 seems to be physical device number.

    So udev returns physical number, and I need to get logical number. Then, i can retrieve data like this: lsusb -D /dev/bus/usb/005/032

    So, how can I get logical device number 032 by physical path like /devices/pci0000:00/0000:00:1d.0/usb5/5-2 ?

  • nutty about natty
    nutty about natty over 9 years
    I'm confused by the different uses of udev vs. lsusb and sys/devices/.. vs. /dev/bus/usb/.. and judging by your answer you seem to be in the know :) Maybe you can shed some light on these two questions? askubuntu.com/questions/342061/power-on-off-usb-ports and askubuntu.com/questions/498950/…
  • Dmitry Frank
    Dmitry Frank over 9 years
    @nuttyaboutnatty, unfortunately I can't give you any clue on your issue (about powering the device down). I'm just learning linux stuff these days, and I'm quite far from any kind of guru. Very little about /sys/devices/... vs /dev/...: /sys is populated by the kernel, it's a representation of actual kernel devices hierarchy. Udev is a user-space daemon that handles /sys hierarchy and populates /dev/... (taking rules in account). So, udev is completely responsible for /dev contents.