Merge remote branch 'grml-scripts/master'
[grml-scripts-core.git] / usr_bin / usbtree
diff --git a/usr_bin/usbtree b/usr_bin/usbtree
new file mode 100755 (executable)
index 0000000..c29eb00
--- /dev/null
@@ -0,0 +1,177 @@
+#!/usr/bin/perl
+#
+# Reads /proc/bus/usb/devices and selectively lists and/or
+# interprets it.
+#
+# Originally written by Randy Dunlap. 
+#
+
+$DEVFILENAME = "/proc/bus/usb/devices";
+$PROGNAME = $0;
+
+if (! open (DEVNUM, "<$DEVFILENAME"))
+{
+       print "$PROGNAME: cannot open '$DEVFILENAME'\n";
+       exit 1;
+}
+
+$showconfig = "yes";
+
+while ($line = <DEVNUM>)       # read a text line from DEVNUM
+{
+       # skip all lines except those we recognize:
+       if (($line !~ "^C:")            # Configuration: one is active
+                   && ($line !~ "^D:") # Device:
+                   && ($line !~ "^I:") # Interface: protocol group
+                   && ($line !~ "^S:") # String: used with root hub
+                   && ($line !~ "^T:") # Topology: starts each device
+                   )
+       {
+               next;   # to the next line
+       }
+
+       chomp $line;            # remove line endings
+
+       # First convert '=' signs to spaces.
+       $line =~ tr/=/ /;
+
+       # and convert all '(' and ')' to spaces.
+       $line =~ tr/(/ /;
+       $line =~ tr/)/ /;
+
+       # split the line at spaces.
+       @fields = split / +/, $line;
+
+       # T:  Bus=01 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0
+       if ($line =~ "^T:")
+       {
+               # split yields: $bus, $level, $parent, $port, $count, $devnum, $speed, $maxchild.
+
+               $bus    = @fields [2];
+               $level  = @fields [4];
+               $parent = @fields [6];          # parent devnum
+               $port   = @fields [8] + 1;      # make $port 1-based
+               $count  = @fields [10];
+               $devnum = @fields [12];
+               $speed  = @fields [14];
+               $maxchild = @fields [16];
+               $devclass = "?";
+               $intclass = "?";
+               $driver   = "?";
+               $ifnum    = "?";
+               $showclass = "?";       # derived from $devclass or $intclass
+               $lastif = "?";                  # show only first altsetting
+               $HCtype = "?";
+               $showconfig = "no";
+               $nconfig = "0";
+               next;
+       } # end T: line
+
+       # only show the _active_ configuration
+       # C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
+       elsif ( $line =~ "^C:" ) {
+           if ( $line =~ "^C:\\*" ) {
+               $showconfig = @fields[4];
+           } else {
+               $showconfig = "no";
+           }
+           next;
+       }
+
+       # D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+       elsif ($line =~ "^D:")
+       { # for D: line
+               $devclass = @fields [5];
+               $nconfig = @fields [13];
+               next;
+       }
+
+       # in case this is a root hub, look at the device strings.
+       #  - S:  Manufacturer:Linux 2.6.5 ehci_hcd      [all 2.6]
+       #  - S:  Product=USB UHCI Root Hub              [all 2.4, 2.2]
+       #  - S:  Product=OPTi Inc 82C861                [2.6/PCI_NAMES]
+       elsif ( $line =~ "^S:" )
+       { # for S: line
+               if ( $level == 00 && $line =~ "hcd" )
+               {
+                   $HCtype = @fields [4];
+               }
+               elsif ( $level == 00 && $line =~ "HCI" && $HCtype eq "?")
+               {
+                   $HCtype = @fields [3];
+               }
+               next;
+       }
+
+       # the rest of this code:
+       #  - only shows interface descriptors
+       #  - for the active configuration
+       #  - for the first (prefer: active!) altsetting
+       elsif ( ! ( $line =~ "^I:" )
+               || "$showconfig" eq "no") {
+           next;
+       }
+
+       
+       # I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=hid
+       $intclass = @fields [9];
+       $ifnum    = @fields [2];
+       $driver   = @fields [15];
+
+       if (($devclass eq ">ifc") || ($devclass eq "unk."))
+       {       # then use InterfaceClass, not DeviceClass
+               $showclass = $intclass;
+       }
+       else
+       {       # use DeviceClass
+               $showclass = $devclass;
+       }
+
+       if ($level == 0)
+       {
+           # substitute real driver name
+           if ( $HCtype =~ "UHCI-alt" )
+           {
+               $HC = "uhci";
+           }
+           elsif ( $HCtype =~ "UHCI" )
+           {
+               $HC = "usb-uhci";
+           }
+           elsif ( $HCtype =~ "OHCI" )
+           {
+               $HC = "usb-ohci";
+           }
+           else
+           {
+               $HC = $HCtype;
+           }
+
+               print sprintf ("/:  Bus $bus.Port $port: Dev $devnum, Class=root_hub, Driver=%s/%sp, %sM\n",
+                        $HC, $maxchild, $speed );
+       }
+       elsif ($lastif ne $ifnum)
+       {
+               $temp = $level;
+               while ($temp >= 1)
+               {
+                       print "    ";
+                       $temp--;
+               }
+
+               if ($nconfig ne "1") {
+                   $temp = " Cfg $showconfig/$nconfig";
+               } else {
+                   $temp = "";
+               }
+
+               print sprintf ("|__ Port $port: Dev $devnum$temp, If $ifnum, Class=$showclass, Driver=$driver%s, %sM\n",
+                       ($maxchild == 0) ? "" : ("/" . $maxchild . "p"),
+                       $speed);
+               $lastif = $ifnum;
+       }
+} # end while DEVNUM
+
+close (DEVNUM);
+
+# END.