Depend on console-tools; drop runit
[grml-scripts.git] / usr_bin / usbtree
1 #!/usr/bin/perl
2 #
3 # Reads /proc/bus/usb/devices and selectively lists and/or
4 # interprets it.
5 #
6 # Originally written by Randy Dunlap. 
7 #
8
9 $DEVFILENAME = "/proc/bus/usb/devices";
10 $PROGNAME = $0;
11
12 if (! open (DEVNUM, "<$DEVFILENAME"))
13 {
14         print "$PROGNAME: cannot open '$DEVFILENAME'\n";
15         exit 1;
16 }
17
18 $showconfig = "yes";
19
20 while ($line = <DEVNUM>)        # read a text line from DEVNUM
21 {
22         # skip all lines except those we recognize:
23         if (($line !~ "^C:")            # Configuration: one is active
24                     && ($line !~ "^D:") # Device:
25                     && ($line !~ "^I:") # Interface: protocol group
26                     && ($line !~ "^S:") # String: used with root hub
27                     && ($line !~ "^T:") # Topology: starts each device
28                     )
29         {
30                 next;   # to the next line
31         }
32
33         chomp $line;            # remove line endings
34
35         # First convert '=' signs to spaces.
36         $line =~ tr/=/ /;
37
38         # and convert all '(' and ')' to spaces.
39         $line =~ tr/(/ /;
40         $line =~ tr/)/ /;
41
42         # split the line at spaces.
43         @fields = split / +/, $line;
44
45         # T:  Bus=01 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0
46         if ($line =~ "^T:")
47         {
48                 # split yields: $bus, $level, $parent, $port, $count, $devnum, $speed, $maxchild.
49
50                 $bus    = @fields [2];
51                 $level  = @fields [4];
52                 $parent = @fields [6];          # parent devnum
53                 $port   = @fields [8] + 1;      # make $port 1-based
54                 $count  = @fields [10];
55                 $devnum = @fields [12];
56                 $speed  = @fields [14];
57                 $maxchild = @fields [16];
58                 $devclass = "?";
59                 $intclass = "?";
60                 $driver   = "?";
61                 $ifnum    = "?";
62                 $showclass = "?";       # derived from $devclass or $intclass
63                 $lastif = "?";                  # show only first altsetting
64                 $HCtype = "?";
65                 $showconfig = "no";
66                 $nconfig = "0";
67                 next;
68         } # end T: line
69
70         # only show the _active_ configuration
71         # C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
72         elsif ( $line =~ "^C:" ) {
73             if ( $line =~ "^C:\\*" ) {
74                 $showconfig = @fields[4];
75             } else {
76                 $showconfig = "no";
77             }
78             next;
79         }
80
81         # D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
82         elsif ($line =~ "^D:")
83         { # for D: line
84                 $devclass = @fields [5];
85                 $nconfig = @fields [13];
86                 next;
87         }
88
89         # in case this is a root hub, look at the device strings.
90         #  - S:  Manufacturer:Linux 2.6.5 ehci_hcd      [all 2.6]
91         #  - S:  Product=USB UHCI Root Hub              [all 2.4, 2.2]
92         #  - S:  Product=OPTi Inc 82C861                [2.6/PCI_NAMES]
93         elsif ( $line =~ "^S:" )
94         { # for S: line
95                 if ( $level == 00 && $line =~ "hcd" )
96                 {
97                     $HCtype = @fields [4];
98                 }
99                 elsif ( $level == 00 && $line =~ "HCI" && $HCtype eq "?")
100                 {
101                     $HCtype = @fields [3];
102                 }
103                 next;
104         }
105
106         # the rest of this code:
107         #  - only shows interface descriptors
108         #  - for the active configuration
109         #  - for the first (prefer: active!) altsetting
110         elsif ( ! ( $line =~ "^I:" )
111                 || "$showconfig" eq "no") {
112             next;
113         }
114
115         
116         # I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=hid
117         $intclass = @fields [9];
118         $ifnum    = @fields [2];
119         $driver   = @fields [15];
120
121         if (($devclass eq ">ifc") || ($devclass eq "unk."))
122         {       # then use InterfaceClass, not DeviceClass
123                 $showclass = $intclass;
124         }
125         else
126         {       # use DeviceClass
127                 $showclass = $devclass;
128         }
129
130         if ($level == 0)
131         {
132             # substitute real driver name
133             if ( $HCtype =~ "UHCI-alt" )
134             {
135                 $HC = "uhci";
136             }
137             elsif ( $HCtype =~ "UHCI" )
138             {
139                 $HC = "usb-uhci";
140             }
141             elsif ( $HCtype =~ "OHCI" )
142             {
143                 $HC = "usb-ohci";
144             }
145             else
146             {
147                 $HC = $HCtype;
148             }
149
150                 print sprintf ("/:  Bus $bus.Port $port: Dev $devnum, Class=root_hub, Driver=%s/%sp, %sM\n",
151                          $HC, $maxchild, $speed );
152         }
153         elsif ($lastif ne $ifnum)
154         {
155                 $temp = $level;
156                 while ($temp >= 1)
157                 {
158                         print "    ";
159                         $temp--;
160                 }
161
162                 if ($nconfig ne "1") {
163                     $temp = " Cfg $showconfig/$nconfig";
164                 } else {
165                     $temp = "";
166                 }
167
168                 print sprintf ("|__ Port $port: Dev $devnum$temp, If $ifnum, Class=$showclass, Driver=$driver%s, %sM\n",
169                         ($maxchild == 0) ? "" : ("/" . $maxchild . "p"),
170                         $speed);
171                 $lastif = $ifnum;
172         }
173 } # end while DEVNUM
174
175 close (DEVNUM);
176
177 # END.