3 # SPDX-License-Identifier: GPL-2.0-only
6 # Some tools emit errors that don't matter (bugs in lspci/PCI firmware and lsusb).
7 # To shown them anyway (e.g. for debugging) comment next line.
10 if [ "$1" = "-h" ]; then
11 printf "Usage: $0 [-h | path to dmesg log]
13 This script tries to find USB ports compatible with USB2/EHCI debug devices and
14 helps you to find their physical locations. To that end, attach at least one
15 uniquely identifiable device to a USB port and run this script. The device needs
16 to be visible in the output of \"lsusb -t\" (debug devices are often *not*!).
18 After determining compatibility of the USB controllers the script will print the
19 devices attached to the debug port as shown by lsusb. If nothing shows up simply
20 switch ports and repeat the process.
22 Note: usually only one port is supported for debugging.\n"
26 if [ "$uid" -ne 0 ]; then
27 echo "Must be run as root. Exiting."
32 find_devs_in_tree
() {
35 busstr
=`printf "Bus %02d" "$bus"`
38 hubs_to_ignore
="8087:0020 8087:0024"
42 # Iterate over the output of lsusb -t because it contains the physical port numbers
43 while IFS
='' read -r line
; do
44 # We need to keep track of the current bus "branch"
45 # Look out for lines starting with /: (that indicate a bus)
46 if [ "${line#*/:}" != "$line" ]; then
47 if [ "${line#*$busstr}" != "$line" ]; then
55 # Skip all lines not belonging to the wanted bus number
56 if [ "$cur_bus" != "$busstr" ]; then
60 # Calculate current USB tier/level
61 spaces
="${line%%[!' ']*}"
62 curlvl
=$
((${#spaces} / 4))
63 if [ $curlvl -ne $reqlvl ]; then
67 # Fetch USB IDs of the current device
68 dev
=`echo ${line#*Dev } | cut -d ',' -f 1`
69 lsusbline
=`lsusb -s "$bus":"$dev"`
70 if [[ ! "$lsusbline" =~ .
*([[:xdigit
:]]{4}:[[:xdigit
:]]{4}) ]]; then
71 printf "Unexpected output from \"%s\": \"%s\"\n" "lsusb -s $bus:$dev" "$usbline"
74 ids
=${BASH_REMATCH[1]}
76 # Skip over rate matching hubs
77 if [[ "$hubs_to_ignore" == *"$ids"* ]]; then
82 # Check for matching physical USB port
83 if [ "${line#*$portstr}" != "$line" ]; then
90 if [ -z "$found" ]; then
95 debug_lspci_devs
=`lspci -nvvD |
96 grep -i "^[0-9a-f]\|debug port" |
97 grep -iB1 --no-group-separator "debug port" |
98 grep -vi "debug port" |
103 if [ -z "$debug_lspci_devs" ]; then
104 printf "No USB controller with debug capability found by lspci.\n
105 Possible reasons: lspci too old, USB controller does not support a debug device, ... Exiting.\n"
108 printf "The following PCI devices support a USB debug port (says lspci): $debug_lspci_devs\n"
110 debug_dmesg_devs_with_port
=`( test -z "$dmesgfile" &&
113 grep -i "ehci.*debug port" |
114 sed "s/.* \([0-9a-f]*:*[0-9a-f]\{2\}:[0-9a-f]\{2\}\.[0-9a-f]\).*ebug port /\1 /" |
117 debug_dmesg_devs
=`echo "$debug_dmesg_devs_with_port" |
121 if [ -z "$debug_dmesg_devs" ]; then
122 printf "dmesg does not show any supported ports.\n
123 Possible reasons: dmesg scrolled off, kernel too old, USB controller does not support a debug device, ... Exiting.\n
124 Note: You can specify a file containing kernel messages as an argument to this program (e.g. /var/log/dmesg)."
128 if [ "$debug_lspci_devs" != "$debug_dmesg_devs" ]; then
129 echo "lspci and the kernel do not agree on USB debug device support. Exiting."
133 printf "and the kernel agrees, good.\n\n"
136 for dev
in $debug_dmesg_devs; do
138 grep "^Bus\|iSerial.*" |
139 grep -B1 --no-group-separator "iSerial.*$dev" |
141 sed "s/Bus *0*\([0-9a-f]*\).*/\1/"`
142 port
=`echo "$debug_dmesg_devs_with_port" |
146 echo "Device(s) currently connected to the debug-capable port $port on PCI device $dev, USB bus $bus:"
148 find_devs_in_tree
"$bus" "$port"
152 echo "Enter 'q' to abort or anything else to repeat"
154 if [ $?
-ne 0 -o "$r" = "q" ]; then