diff options
Diffstat (limited to 'usb-devices')
-rwxr-xr-x | usb-devices | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/usb-devices b/usb-devices new file mode 100755 index 0000000..f5763da --- /dev/null +++ b/usb-devices @@ -0,0 +1,198 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2009 Greg Kroah-Hartman <greg@kroah.com> +# Copyright (c) 2009 Randy Dunlap <rdunlap@xenotime.net> +# Copyright (c) 2009 Frans Pop <elendil@planet.nl> +# +# When checking with shellcheck ignore +# "In POSIX sh, local is undefined." +# every modern shell supports it. +# shellcheck disable=SC3043 + +print_string() { + file=$1 + name=$2 + if [ -f "$file" ]; then + echo "S: $name=$(cat "$file")" + fi +} + +class_decode() { + class=$1 # v4: in hex + + case $class in + "00") echo ">ifc " ;; + "01") echo "audio" ;; + "02") echo "commc" ;; + "03") echo "HID " ;; + "05") echo "PID " ;; + "06") echo "still" ;; + "07") echo "print" ;; + "08") echo "stor." ;; + "09") echo "hub " ;; + "0a") echo "data " ;; + "0b") echo "scard" ;; + "0d") echo "c-sec" ;; + "0e") echo "video" ;; + "0f") echo "perhc" ;; + "10") echo "av " ;; + "11") echo "blbrd" ;; + "12") echo "bridg" ;; + "dc") echo "diagd" ;; + "e0") echo "wlcon" ;; + "ef") echo "misc " ;; + "fe") echo "app. " ;; + "ff") echo "vend." ;; + "*") echo "unk. " ;; + esac +} + +print_endpoint() { + eppath=$1 + + read -r addr < "$eppath/bEndpointAddress" + read -r attr < "$eppath/bmAttributes" + read -r dir < "$eppath/direction" + + if [ "$dir" = "in" ]; then + dir="I" + elif [ "$dir" = "out" ]; then + dir="O" + elif [ "$dir" = "both" ]; then + dir="B" + fi + + read -r eptype < "$eppath/type" + if [ "$eptype" = Control ]; then + eptype="Ctrl" + elif [ "$eptype" = Interrupt ]; then + eptype="Int." + fi + + read -r maxps_hex < "$eppath/wMaxPacketSize" + maxps_hex="0x$maxps_hex" + # Extract MaxPS size (bits 0-10) and multiplicity values (bits 11-12) + + maxps=$(($(printf "%4i*%s\n" $((maxps_hex & 0x7ff)) \ + $((1 + ((maxps_hex >> 11) & 0x3)))))) + + read -r interval < "$eppath/interval" + + printf "E: Ad=%s(%s) Atr=%s(%s) MxPS=%4s Ivl=%s\n" \ + "$addr" "$dir" "$attr" "$eptype" "$maxps" "$interval" +} + +print_interface() { + ifpath=$1 + + read -r ifnum < "$ifpath/bInterfaceNumber" + read -r altset < "$ifpath/bAlternateSetting" + read -r numeps < "$ifpath/bNumEndpoints" + read -r class < "$ifpath/bInterfaceClass" + read -r subclass < "$ifpath/bInterfaceSubClass" + read -r protocol < "$ifpath/bInterfaceProtocol" + + if [ -L "$ifpath/driver" ]; then # v4: allow for no driver + driver=$(readlink "$ifpath/driver") + driver=${driver##*/} + else + driver="(none)" + fi + classname=$(class_decode "$class") + printf "I: If#=%2i Alt=%2i #EPs=%2i Cls=%s(%s) Sub=%s Prot=%s Driver=%s\n" \ + "0x${ifnum#0}" "${altset#0}" "0x${numeps#0}" "$class" "$classname" "$subclass" \ + "$protocol" "$driver" + + for endpoint in "$ifpath"/ep_?? + do + if [ -L "$endpoint" ] || [ -d "$endpoint" ]; then # v4: verify endpoint exists + print_endpoint "$endpoint" + fi + done +} + +print_device() { + local devpath=$1 + local parent=$2 + local level=$3 + local count=$4 + + [ -d "$devpath" ] || return + cd "$devpath" || return + + read -r busnum < "busnum" + read -r devnum < "devnum" + + if [ "$level" -gt 0 ]; then + port=$((${devpath##*[-.]} - 1)) + else + port=0 + fi + + read -r speed < "speed" + read -r maxchild < "maxchild" + printf "\nT: Bus=%02i Lev=%02i Prnt=%02i Port=%02i Cnt=%02i Dev#=%3i Spd=%-4s MxCh=%2i\n" \ + "$busnum" "$level" "$parent" "$port" "$count" "$devnum" "$speed" "$maxchild" + + read -r ver < "version" + read -r devclass < "bDeviceClass" + read -r devsubclass < "bDeviceSubClass" + read -r devprotocol < "bDeviceProtocol" + read -r maxps0 < "bMaxPacketSize0" + read -r numconfigs < "bNumConfigurations" + classname="$(class_decode "$devclass")" + printf "D: Ver=%5s Cls=%s(%s) Sub=%s Prot=%s MxPS=%2i #Cfgs=%3i\n" \ + "$ver" "$devclass" "$classname" "$devsubclass" "$devprotocol" \ + "$maxps0" "$numconfigs" + + read -r vendid < "idVendor" + read -r prodid < "idProduct" + read -r bcddevice < "bcdDevice" + revmajor="${bcddevice%%??}" + revminor="${bcddevice##??}" + printf "P: Vendor=%s ProdID=%s Rev=%s.%s\n" \ + "$vendid" "$prodid" "$revmajor" "$revminor" + + print_string manufacturer "Manufacturer" + print_string product Product + print_string serial SerialNumber + + read -r numifs < "bNumInterfaces" + read -r cfgnum < "bConfigurationValue" + read -r attr < "bmAttributes" + read -r maxpower < "bMaxPower" + printf "C: #Ifs=%2i Cfg#=%2i Atr=%s MxPwr=%s\n" \ + "$numifs" "$cfgnum" "$attr" "$maxpower" + + # There's not really any useful info in endpoint 00 + #print_endpoint $devpath/ep_00 + + for interface in "$busnum"-*:?.* + do + print_interface "$devpath/$interface" + done + + devcount=0 + for subdev in "$busnum"-* + do + echo "$subdev" | grep -Eq "^$busnum-[0-9]+(\.[0-9]+)*$" \ + || continue + + devcount=$((devcount + 1)) + if [ -d "$devpath/$subdev" ]; then + print_device "$devpath/$subdev" \ + "$devnum" "$((level +1))" "$devcount" + fi + done +} + +if [ ! -d /sys/bus ]; then + echo "Error: directory /sys/bus does not exist; is sysfs mounted?" >&2 + exit 1 +fi + +for device in $(find /sys/bus/usb/devices -name 'usb*' -printf '%f\n' | sort -V) +do + print_device "/sys/bus/usb/devices/$device" 0 0 0 +done |