find_usbdebug.sh
1 #!/usr/bin/env bash 2 3 # SPDX-License-Identifier: GPL-2.0-only 4 5 LANG=C 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. 8 exec 2>/dev/null 9 10 if [ "$1" = "-h" ]; then 11 printf "Usage: $0 [-h | path to dmesg log] 12 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*!). 17 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. 21 22 Note: usually only one port is supported for debugging.\n" 23 exit 0 24 fi 25 uid=`id -u` 26 if [ "$uid" -ne 0 ]; then 27 echo "Must be run as root. Exiting." 28 exit 1 29 fi 30 31 if ! command -v lsusb; then 32 echo "lsusb not found. Please install \"usbutils\" from your 33 distribution's package manager. Exiting." 34 exit 1 35 fi 36 37 if ! command -v lspci; then 38 echo "lspci not found. Please install \"pciutils\" from your 39 distribution's package manager. Exiting." 40 exit 1 41 fi 42 43 dmesgfile=$1 44 45 find_devs_in_tree () { 46 bus=$1 47 port=$2 48 49 # lsusb -t uses 3 digits for bus/port nunmbers as of version 016 and later 50 if [ $(lsusb -V | cut -f 3 -d " ") -lt 16 ]; then 51 busstr=`printf "Bus %02d" "$bus"` 52 portstr="Port $port" 53 else 54 busstr=`printf "Bus %03d" "$bus"` 55 portstr=`printf "Port %03d" "$port"` 56 fi 57 58 hubs_to_ignore="8087:0020 8087:0024 8087:8000 8087:8008" 59 reqlvl=1 60 61 found= 62 # Iterate over the output of lsusb -t because it contains the physical port numbers 63 while IFS='' read -r line; do 64 # We need to keep track of the current bus "branch" 65 # Look out for lines starting with /: (that indicate a bus) 66 if [ "${line#*/:}" != "$line" ]; then 67 if [ "${line#*$busstr}" != "$line" ]; then 68 cur_bus=$busstr 69 else 70 cur_bus= 71 fi 72 continue 73 fi 74 75 # Skip all lines not belonging to the wanted bus number 76 if [ "$cur_bus" != "$busstr" ]; then 77 continue 78 fi 79 80 # Calculate current USB tier/level 81 spaces="${line%%[!' ']*}" 82 curlvl=$((${#spaces} / 4)) 83 if [ $curlvl -ne $reqlvl ]; then 84 continue 85 fi 86 87 # Fetch USB IDs of the current device 88 dev=`echo ${line#*Dev } | cut -d ',' -f 1` 89 lsusbline=`lsusb -s "$bus":"$dev"` 90 if [[ ! "$lsusbline" =~ .*([[:xdigit:]]{4}:[[:xdigit:]]{4}) ]]; then 91 printf "Unexpected output from \"%s\": \"%s\"\n" "lsusb -s $bus:$dev" "$usbline" 92 exit 1 93 fi 94 ids=${BASH_REMATCH[1]} 95 96 # Skip over rate matching hubs 97 if [[ "$hubs_to_ignore" == *"$ids"* ]]; then 98 ((reqlvl += 1)) 99 continue 100 fi 101 102 # Check for matching physical USB port 103 if [ "${line#*$portstr}" != "$line" ]; then 104 echo "$lsusbline" 105 return 106 fi 107 done<< EOF 108 $(lsusb -t) 109 EOF 110 if [ -z "$found" ]; then 111 echo "none" 112 fi 113 } 114 115 debug_lspci_devs=`lspci -nvvD | 116 grep -i "^[0-9a-f]\|debug port" | 117 grep -iB1 --no-group-separator "debug port" | 118 grep -vi "debug port" | 119 cut -f 1 -d" " | 120 sort | 121 xargs echo` 122 123 if [ -z "$debug_lspci_devs" ]; then 124 printf "No USB controller with debug capability found by lspci.\n 125 Possible reasons: lspci too old, USB controller does not support a debug device, ... Exiting.\n" 126 exit 1 127 fi 128 printf "The following PCI devices support a USB debug port (says lspci): $debug_lspci_devs\n" 129 130 debug_dmesg_devs_with_port=`( test -z "$dmesgfile" && 131 dmesg || 132 cat "$dmesgfile") | 133 grep -i "ehci.*debug port" | 134 sed "s/.* \([0-9a-f]*:*[0-9a-f]\{2\}:[0-9a-f]\{2\}\.[0-9a-f]\).*ebug port /\1 /" | 135 sort` 136 137 debug_dmesg_devs=`echo "$debug_dmesg_devs_with_port" | 138 cut -f 1 -d" " | 139 xargs echo` 140 141 if [ -z "$debug_dmesg_devs" ]; then 142 printf "dmesg does not show any supported ports.\n 143 Possible reasons: dmesg scrolled off, kernel too old, USB controller does not support a debug device, ... Exiting.\n 144 Note: You can specify a file containing kernel messages as an argument to this program (e.g. /var/log/dmesg)." 145 exit 1 146 fi 147 148 if [ "$debug_lspci_devs" != "$debug_dmesg_devs" ]; then 149 echo "lspci and the kernel do not agree on USB debug device support. Exiting." 150 exit 1 151 fi 152 153 printf "and the kernel agrees, good.\n\n" 154 155 while true; do 156 for dev in $debug_dmesg_devs; do 157 bus=`lsusb -v | 158 grep "^Bus\|iSerial.*" | 159 grep -B1 --no-group-separator "iSerial.*$dev" | 160 grep "^Bus" | 161 sed "s/Bus *0*\([0-9a-f]*\).*/\1/"` 162 port=`echo "$debug_dmesg_devs_with_port" | 163 grep "^$dev" | 164 cut -f 2 -d" "` 165 166 echo "Device(s) currently connected to the debug-capable port $port on PCI device $dev, USB bus $bus:" 167 168 find_devs_in_tree "$bus" "$port" 169 echo 170 done 171 172 echo "Enter 'q' to abort or anything else to repeat" 173 read -r r 174 if [ $? -ne 0 -o "$r" = "q" ]; then 175 break; 176 fi 177 done 178 179 exit 0