#! /bin/sh
set -e

# List USB devices in or connected to the system.
# Based on usb-devices.sh script from Greg KH and Randy Dunlap;
# adapted for use in Debian Installer by Frans Pop.

print_string() {
	local file=$1
	local name=$2
	if [ -f $file ]; then
		echo "   $name: $(cat $file)"
	fi
}

class_decode() {
	local class=$1

	case $class in
		00) echo ">ifc " ;;
		01) echo "audio" ;;
		02) echo "commc" ;;
		03) echo "HID  " ;;
		05) echo "phys " ;;
		06) echo "image" ;;
		07) echo "print" ;;
		08) echo "mstor" ;;
		09) echo "hub  " ;;
		0a) echo "comdt" ;;
		0b) echo "smcrd" ;;
		0d) echo "cosec" ;;
		0e) echo "video" ;;
		0f) echo "perhc" ;;
		dc) echo "diagd" ;;
		e0) echo "wlcon" ;;
		ef) echo "misc " ;;
		fe) echo "app. " ;;
		ff) echo "vend." ;;
		*)  echo "unk. " ;;
	esac
}

print_interface() {
	local if=$1

	ifnum=$(cat $if/bInterfaceNumber)
	class=$(cat $if/bInterfaceClass)
	devsubclass=$(cat $if/bInterfaceSubClass)
	devprotocol=$(cat $if/bInterfaceProtocol)
	if [ -L $if/driver ]; then
		driver=$(basename $(readlink $if/driver))
	else
		driver="<none>"
	fi
	classname=$(class_decode $class)
	printf "   Interface %s: Class %s(%s) Subclass %s Protocol %s Driver %s\n" \
		$ifnum $class "$classname" $devsubclass $devprotocol $driver
}

print_device() {
	local devpath=$1
	local parent=$2
	local level=$3

	[ -d $devpath ] || return
	cd $devpath

	local busnum=$(cat busnum)
	local devnum=$(cat devnum)

	vendid=$(cat idVendor)
	prodid=$(cat idProduct)
	if [ -r product ]; then
		product=$(cat product)
	else
		procuct="N/A"
	fi
	printf "\nBus %02i Device %02i: %s [%s:%s]\n" \
		$busnum $devnum "$product" $vendid $prodid

	if [ $level -gt 0 ]; then
		port=$((${devpath##*[-.]} - 1))
	else
		port=0
	fi
	devclass=$(cat bDeviceClass)
	devsubclass=$(cat bDeviceSubClass)
	devprotocol=$(cat bDeviceProtocol)
	classname=$(class_decode $devclass)
	printf "   Level %02i Parent %02i Port %02i  Class %s(%s) Subclass %s Protocol %s\n" \
		$level $parent $port $devclass "$classname" $devsubclass $devprotocol

	print_string manufacturer Manufacturer
	#print_string serial SerialNumber

	for interface in $busnum-*:?.*; do
		print_interface $devpath/$interface
	done

	for subdev in $busnum-*; do
		echo "$subdev" | grep -Eq "^$busnum-[0-9]+(\.[0-9]+)*$" \
			|| continue

		if [ -d $devpath/$subdev ]; then
			print_device $devpath/$subdev $devnum $(($level +1))
		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 /sys/bus/usb/devices/usb*; do
	print_device $device 0 0
done
