-
Notifications
You must be signed in to change notification settings - Fork 129
/
tlp-usblist
120 lines (103 loc) · 3.51 KB
/
tlp-usblist
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/perl
# tlp-usblist - list usb device info with autosuspend attributes
#
# Copyright (c) 2024 Thomas Koch <linrunner at gmx.net> and others.
# SPDX-License-Identifier: GPL-2.0-or-later
package tlp_usblist;
use strict;
use warnings;
# --- Constants
use constant USBD => "/sys/bus/usb/devices";
# --- Modules
use Getopt::Long;
# --- Global vars
my %usbdevices;
my $verbose = 0;
# --- Subroutines
# Read content from a sysfile
# $_[0]: input file
# return: content / empty string if nonexistent or not readable
sub catsysf {
my $fname = "$_[0]";
my $sysval = "";
if ( open (my $sysf, "<", $fname) ) {
chomp ($sysval = <$sysf>);
close ($sysf);
}
return $sysval;
}
# Read device driver from DEVICE/uevent
# $_[0]: (sub)device base path
# return: driver / empty string if uevent nonexistent or not readable
sub getdriver {
my $dpath = "$_[0]";
my $driver = "";
if ( open (my $sysf, "<", $dpath . "/uevent") ) {
# read file line by line
while (<$sysf>) {
# match line content and return DRIVER= value
if ( s/^DRIVER=(.*)/$1/ ) {
chomp ($driver = $_);
last; # break loop
}
}
close ($sysf);
}
return $driver
}
# Get drivers associated with USB device by iterating subdevices
# $_[0]: device base path
# return: driver list / "no driver" if none found
sub usbdriverlist {
my $dpath = "$_[0]";
my $driverlist = "";
# iterate subdevices
foreach my $subdev (glob $dpath . "/*:*") {
# get subdevice driver
my $driver = getdriver ("$subdev");
if ( $driver ) {
if (index ($driverlist, $driver) == -1) {
if ($driverlist) { $driverlist = $driverlist . ", " . $driver; }
else { $driverlist = $driver; }
} # if index
} # if $driver
} # foreach $subdev
if (! $driverlist) { $driverlist = "no driver"; }
return $driverlist
}
# --- MAIN
# parse arguments
GetOptions ('verbose' => \$verbose);
# Read USB device tree attributes as arrays into %usbdevices hash, indexed by Bus_Device
foreach my $udev (grep { ! /:/ } glob USBD . "/*") {
my $usbv = "(autosuspend not available)";
# get device id
my $usbk = sprintf ("%03d_%03d", catsysf ("$udev/busnum"), catsysf ("$udev/devnum") );
# get device mode and timeout
if ( length (my $ptimeout = catsysf ("$udev/power/autosuspend_delay_ms"))
&& length (my $pmode = catsysf ("$udev/power/control")) ) {
if ( $verbose ) {
# get device status
my $pstatus = catsysf ("$udev/power/runtime_status");
# format: device mode, timeout, status
$usbv = sprintf ("control = %-5s autosuspend_delay_ms = %4d, runtime_status = %-9s", $pmode . ",", $ptimeout, $pstatus);
} else {
# format: device mode, timeout
$usbv = sprintf ("control = %-5s autosuspend_delay_ms = %4d", $pmode . ",", $ptimeout);
}
}
# store formatted result in hash
@{$usbdevices{$usbk}} = ($udev, $usbv);
}
# Output device list with attributes and drivers
foreach (`lsusb 2> /dev/null`) {
my ($bus, $dev, $usbid, $desc) = /Bus (\S+) Device (\S+): ID (\S+)[ ]+(.*)/;
if (length ($bus) and length ($dev) and length ($usbid) ) {
my $usbk = $bus . "_" . $dev;
$desc =~ s/\s+$//;
$desc ||= "<unknown>";
print "Bus $bus Device $dev ID $usbid $usbdevices{$usbk}[1] -- $desc ("
. usbdriverlist($usbdevices{$usbk}[0]) . ")\n";
}
}
exit 0;