@@ -2,7 +2,7 @@
#
# sensors-detect - Detect hardware monitoring chips
# Copyright (C) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>
-# Copyright (C) 2004 - 2012 Jean Delvare <khali@linux-fr.org>
+# Copyright (C) 2004 - 2013 Jean Delvare <khali@linux-fr.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -39,9 +39,9 @@
use constant NO_CACHE => 1;
use vars qw(@pci_adapters @chip_ids @ipmi_ifs @non_hwmon_chip_ids
- $i2c_addresses_to_scan $revision @i2c_byte_cache);
+ $i2c_addresses_to_scan $revision @i2c_byte_cache %opt);
-$revision = '$Revision: 6170 $ ($Date: 2013-05-20 21:25:22 +0200 (lun. 20 mai 2013) $)';
+$revision = '$Revision: 6209 $ ($Date: 2014-01-14 22:51:58 +0100 (mar. 14 janv. 2014) $)';
$revision =~ s/\$\w+: (.*?) \$/$1/g;
$revision =~ s/ \([^()]*\)//;
@@ -1028,6 +1028,11 @@
i2c_addrs => [0x4c, 0x4d],
i2c_detect => sub { lm90_detect(@_, 17); },
}, {
+ name => "Texas Instruments TMP451",
+ driver => "lm90",
+ i2c_addrs => [0x4c],
+ i2c_detect => sub { lm90_detect(@_, 18); },
+ }, {
name => "Texas Instruments AMC6821",
driver => "amc6821",
i2c_addrs => [0x18..0x1a, 0x2c..0x2e, 0x4c..0x4e],
@@ -1235,6 +1240,11 @@
i2c_addrs => [0x2e],
i2c_detect => sub { emc1403_detect(@_, 2); },
}, {
+ name => "SMSC EMC2104",
+ driver => "to-be-written",
+ i2c_addrs => [0x2f],
+ i2c_detect => sub { emc1403_detect(@_, 13); },
+ }, {
name => "Fintek F75121R/F75122R/RG (VID+GPIO)",
driver => "to-be-written",
i2c_addrs => [0x4e], # 0x37 not probed
@@ -2031,6 +2041,13 @@
logdev => 0x0b,
features => FEAT_IN | FEAT_FAN | FEAT_TEMP,
}, {
+ name => "Nuvoton NCT6681D/NCT6682D eSIO",
+ driver => "to-be-written",
+ devid => 0xB270,
+ devid_mask => 0xFFF0,
+ logdev => 0x0b,
+ features => FEAT_IN | FEAT_FAN | FEAT_TEMP,
+ }, {
name => "Nuvoton W83667HG-B (NCT5571D) Super IO Sensors",
driver => "w83627ehf",
devid => 0xB350,
@@ -2063,6 +2080,20 @@
logdev => 0x0b,
features => FEAT_IN | FEAT_FAN | FEAT_TEMP,
}, {
+ name => "Nuvoton NCT6683D eSIO",
+ driver => "to-be-written",
+ devid => 0xC730,
+ devid_mask => 0xFFF0,
+ logdev => 0x0b,
+ features => FEAT_IN | FEAT_FAN | FEAT_TEMP,
+ }, {
+ name => "Nuvoton NCT6791D Super IO Sensors",
+ driver => "nct6775",
+ devid => 0xC800,
+ devid_mask => 0xFFF0,
+ logdev => 0x0b,
+ features => FEAT_IN | FEAT_FAN | FEAT_TEMP,
+ }, {
name => "Nuvoton NCT6102D/NCT6104D/NCT6106D Super IO Sensors",
driver => "to-be-written", # nct6775
devid => 0xC450,
@@ -2094,6 +2125,12 @@
logdev => 0x04,
features => FEAT_IN | FEAT_FAN | FEAT_TEMP,
}, {
+ name => "Fintek F71868A Super IO Sensors",
+ driver => "to-be-written",
+ devid => 0x1106,
+ logdev => 0x04,
+ features => FEAT_IN | FEAT_FAN | FEAT_TEMP,
+ }, {
name => "Fintek F71869F/E Super IO Sensors",
driver => "f71882fg",
devid => 0x0814,
@@ -2182,6 +2219,12 @@
@superio_ids_ite = (
{
+ name => "ITE IT8603E Super IO Sensors",
+ driver => "it87",
+ devid => 0x8603,
+ logdev => 0x04,
+ features => FEAT_IN | FEAT_FAN | FEAT_TEMP,
+ }, {
name => "ITE IT8702F Super IO Fan Sensors",
driver => "to-be-written",
devid => 0x8702,
@@ -2365,7 +2408,7 @@
}, {
name => "AMD Family 15h thermal sensors",
driver => "k10temp",
- detect => sub { amd_pci_detect('1603') },
+ detect => sub { amd_pci_detect('1603', '1403', '141d') },
}, {
name => "AMD Family 15h power sensors",
driver => "fam15h_power",
@@ -2483,6 +2526,16 @@
return %result;
}
+# Read answer from stdin or accept default answer automatically
+sub read_answer
+{
+ if ($opt{auto}) {
+ print "\n";
+ return "";
+ }
+ return <STDIN> || "";
+}
+
###################
# I/O PORT ACCESS #
###################
@@ -2616,11 +2669,12 @@
# [2] -> SUBLEVEL
# [3] -> EXTRAVERSION
#
-use vars qw(@kernel_version $kernel_arch);
+use vars qw($kernel_version @kernel_version $kernel_arch);
sub initialize_kernel_version
{
- `uname -r` =~ /(\d+)\.(\d+)\.(\d+)(.*)/;
+ chomp($kernel_version = `uname -r`);
+ $kernel_version =~ /(\d+)\.(\d+)\.(\d+)(.*)/;
@kernel_version = ($1, $2, $3, $4);
chomp($kernel_arch = `uname -m`);
@@ -2656,7 +2710,10 @@
while (<INPUTFILE>) {
if (m/^processor\s*:\s*(\d+)/) {
push @cpu, $entry if scalar keys(%{$entry}); # Previous entry
- $entry = { nr => $1 }; # New entry
+ $entry = { # New entry
+ nr => $1,
+ vendor_id => "undefined",
+ };
next;
}
if (m/^(vendor_id|cpu family|model|model name|stepping|cpuid level)\s*:\s*(.+)$/) {
@@ -2743,7 +2800,7 @@
# First try to get the I2C adapter driver name from sysfs,
# and if it fails, fall back to searching our list of known
# I2C adapters.
- $entry->{driver} = sysfs_device_driver($entry->{parent})
+ $entry->{driver} = sysfs_device_module($entry->{parent})
|| find_i2c_adapter_driver($entry->{name})
|| 'UNKNOWN';
@@ -2766,7 +2823,7 @@
while (defined($hwmon = readdir(HWMON))) {
next unless $hwmon =~ m/^hwmon\d+$/;
- $driver = sysfs_device_driver("${class_dir}/$hwmon/device");
+ $driver = sysfs_device_module("${class_dir}/$hwmon/device");
next unless defined($driver);
if (device_driver_autoloads("${class_dir}/$hwmon/device")) {
@@ -2788,24 +2845,23 @@
# MODULES #
###########
-use vars qw(%modules_list %modules_supported @modules_we_loaded);
+use vars qw(%modules_builtin %modules_list %modules_supported @modules_we_loaded);
sub initialize_modules_list
{
- local $_;
+ local ($_, *INPUTFILE);
- # /sys/module contains built-in drivers too, but doesn't exist on
- # older kernels (added in kernel 2.6.7)
- if (opendir(local *MODULES, "$sysfs_root/module")) {
- while (defined($_ = readdir(MODULES))) {
- next if m/^\./;
- $modules_list{$1} = 1 if m/^(\S*)/;
+ # Starting with kernel 2.6.33, a list of built-in modules is available
+ if (open(*INPUTFILE, "/lib/modules/$kernel_version/modules.builtin")) {
+ while (<INPUTFILE>) {
+ tr/-/_/;
+ $modules_builtin{$1} = 1 if m/\/([^\/]+)\.ko$/;
}
- return;
+ close(INPUTFILE);
}
- # Fall back to /proc/modules as it is always available
- open(local *INPUTFILE, "/proc/modules") or return;
+ # List all loaded modules
+ open(*INPUTFILE, "/proc/modules") or return;
while (<INPUTFILE>) {
$modules_list{$1} = 1 if m/^(\S*)/;
}
@@ -2815,7 +2871,14 @@
{
my $module = shift;
$module =~ tr/-/_/;
- return exists $modules_list{$module}
+ return exists $modules_list{$module} || exists $modules_builtin{$module};
+}
+
+sub is_module_builtin
+{
+ my $module = shift;
+ $module =~ tr/-/_/;
+ return exists $modules_builtin{$module};
}
sub load_module
@@ -3004,8 +3067,8 @@
# SYSFS HELPERS #
#################
-# From a sysfs device path, return the driver (module) name, or undef
-sub sysfs_device_driver
+# From a sysfs device path, return the module name, or undef
+sub sysfs_device_module
{
my $device = shift;
@@ -3014,6 +3077,16 @@
return basename($link);
}
+# From a sysfs device path, return the driver name, or undef
+sub sysfs_device_driver
+{
+ my $device = shift;
+
+ my $link = readlink("$device/driver");
+ return unless defined $link;
+ return basename($link);
+}
+
# From a sysfs device path, return the subsystem name, or undef
sub sysfs_device_subsystem
{
@@ -3594,11 +3667,12 @@
# If the address is busy, we can normally find out which driver
# requested it (if the kernel is recent enough, at least 2.6.16 and
# later are known to work), and we assume it is the right one.
- my ($device, $driver, $new_hash);
+ my ($device, $driver, $module, $new_hash);
$device = sprintf("$sysfs_root/bus/i2c/devices/\%d-\%04x",
$adapter_nr, $addr);
$driver = sysfs_device_driver($device);
+ $module = sysfs_device_module($device);
if (!defined($driver)) {
printf("Client at address 0x%02x can not be probed - ".
@@ -3615,14 +3689,21 @@
};
printf "Client found at address 0x\%02x\n", $addr;
- printf "Handled by driver `\%s' (already loaded), chip type `\%s'\n",
- $driver, $new_hash->{chipname};
+ if (defined($module)) {
+ printf "Handled by driver `\%s' (already loaded), chip type `\%s'\n",
+ $module, $new_hash->{chipname};
+ } else {
+ printf "Handled by driver `\%s' (built-in), chip type `\%s'\n",
+ $driver, $new_hash->{chipname};
+ # Let's hope that the driver name matches the module name
+ $module = $driver;
+ }
# Only add it to the list if this is something we would have detected,
# else we end up with random i2c chip drivers listed (for example
# media/video drivers.)
- if (exists $modules_supported{$driver}) {
- add_i2c_to_chips_detected($driver, $new_hash);
+ if (exists $modules_supported{$module}) {
+ add_i2c_to_chips_detected($module, $new_hash);
} else {
print " (note: this is probably NOT a sensor chip!)\n";
}
@@ -3707,7 +3788,7 @@
"Do you want to scan it? (\%s/selectively): ",
$default ? "YES/no" : "yes/NO";
- $input = <STDIN>;
+ $input = read_answer();
if ($input =~ /^\s*n/i
|| (!$default && $input !~ /^\s*[ys]/i)) {
print "\n";
@@ -3718,7 +3799,7 @@
print "Please enter one or more addresses not to scan. Separate them with commas.\n",
"You can specify a range by using dashes. Example: 0x58-0x5f,0x69.\n",
"Addresses: ";
- $input = <STDIN>;
+ $input = read_answer();
chomp($input);
@not_to_scan = parse_not_to_scan(0x03, 0x77, $input);
} elsif (($class & 0xff00) == 0x0300) {
@@ -4498,7 +4579,7 @@
# 8 = W83L771W/G, 9 = TMP401, 10 = TMP411,
# 11 = W83L771AWG/ASG, 12 = MAX6690,
# 13 = ADT7461A/NCT1008, 14 = SA56004,
-# 15 = G781, 16 = TMP431, 17 = TMP432
+# 15 = G781, 16 = TMP431, 17 = TMP432, 18 = TMP451
# Registers used:
# 0x03: Configuration
# 0x04: Conversion rate
@@ -4628,6 +4709,12 @@
return if $mid != 0x55; # Texas Instruments
return 6 if ($cid == 0x32); # TMP432A/B
}
+ if ($chip == 18) {
+ return if ($conf & 0x1B) != 0;
+ return if $rate > 0x09;
+ return if $mid != 0x55; # Texas Instruments
+ return 4 if ($cid == 0x00); # TMP451
+ }
return;
}
@@ -5516,8 +5603,7 @@
# Extra checks for MAX1617 and LM84, since those are often misdetected.
# We verify several assertions (6 for the MAX1617, 4 for the LM84) and
- # discard the chip if any fail. Note that these checks are not done
- # by the adm1021 driver.
+ # discard the chip if any fail.
if ($chip == 2 || $chip == 5) {
my $lte = i2c_smbus_read_byte_data($file, 0x00);
my $rte = i2c_smbus_read_byte_data($file, 0x01);
@@ -5882,7 +5968,8 @@
# Chip to detect: 0 = EMC1403, 1 = EMC1404, 2 = EMC2103, 3 = EMC1423,
# 4 = EMC1002, 5 = EMC1033, 6 = EMC1046, 7 = EMC1047, 8 = EMC1072,
-# 9 = EMC1073, 10 = EMC1074, 11 = EMC1402, 12 = EMC1424
+# 9 = EMC1073, 10 = EMC1074, 11 = EMC1402, 12 = EMC1424,
+# 13 = EMC2104
# Registers used:
# 0xfd: Device ID register
# 0xfe: Vendor ID register
@@ -5935,6 +6022,9 @@
} elsif ($chip == 12) { # EMC1424
return unless $dev_id == 0x27;
return unless $rev == 0x01;
+ } elsif ($chip == 13) { # EMC2104
+ return unless $dev_id == 0x1d;
+ return unless $rev == 0x02;
}
return 6;
@@ -6381,9 +6471,11 @@
sub amd_pci_detect
{
- my $f3_id = shift;
- return unless exists $pci_list{"1022:$f3_id"};
- return 9;
+ my $dev_id;
+ while (defined($dev_id = shift)) {
+ return 9 if exists $pci_list{"1022:$dev_id"};
+ }
+ return undef;
}
sub fam10h_pci_detect
@@ -6620,7 +6712,7 @@
if ($driver eq "to-be-written") {
print "Note: there is no driver for ${$chips_detected{$driver}}[0]{chipname} yet.\n".
"Check http://www.lm-sensors.org/wiki/Devices for updates.\n\n";
- } else {
+ } elsif (!is_module_builtin($driver)) {
open(local *INPUTFILE, "modprobe -l $driver 2>/dev/null |");
local $_;
my $modulefound = 0;
@@ -6635,8 +6727,7 @@
# isn't supported
if ((($? >> 8) == 0) && ! $modulefound) {
print "Warning: the required module $driver is not currently installed\n".
- "on your system. If it is built into the kernel then it's OK.\n".
- "Otherwise, check http://www.lm-sensors.org/wiki/Devices for\n".
+ "on your system. Check http://www.lm-sensors.org/wiki/Devices for\n".
"driver availability.\n\n";
} else {
$hwmon_modules{$driver}++
@@ -6659,7 +6750,7 @@
printf "Do you want to \%s /etc/modprobe.d/lm_sensors.conf? (\%s): ",
(-e '/etc/modprobe.d/lm_sensors.conf' ? 'overwrite' : 'generate'),
($have_modprobe_d ? 'YES/no' : 'yes/NO');
- $_ = <STDIN>;
+ $_ = read_answer();
if (($have_modprobe_d and not m/^\s*n/i) or m/^\s*y/i) {
unless ($have_modprobe_d) {
mkdir('/etc/modprobe.d', 0777)
@@ -6683,7 +6774,7 @@
printf "Do you want to \%s /etc/sysconfig/lm_sensors? (\%s): ",
(-e '/etc/sysconfig/lm_sensors' ? 'overwrite' : 'generate'),
($have_sysconfig ? 'YES/no' : 'yes/NO');
- $_ = <STDIN>;
+ $_ = read_answer();
if (($have_sysconfig and not m/^\s*n/i) or m/^\s*y/i) {
unless ($have_sysconfig) {
mkdir('/etc/sysconfig', 0777)
@@ -6752,21 +6843,30 @@
"/usr/local/bin/sensors -s\n").
"#----cut here----\n\n");
- print "If you have some drivers built into your kernel, the list above will\n".
- "contain too many modules. Skip the appropriate ones! You really\n".
- "should try these commands right now to make sure everything is\n".
- "working properly. Monitoring programs won't work until the needed\n".
+ print "You really should try these commands right now to make sure everything\n".
+ "is working properly. Monitoring programs won't work until the needed\n".
"modules are loaded.\n\n";
}
-
}
sub main
{
my ($input, $superio_features);
- # Handle special command line cases first
- if (defined $ARGV[0] && $ARGV[0] eq "--stat") {
+ # Parse command line options
+ while (defined $ARGV[0]) {
+ if ($ARGV[0] eq "--stat") {
+ $opt{stat} = 1;
+ } elsif ($ARGV[0] eq "--auto") {
+ $opt{auto} = 1;
+ } else {
+ print STDERR "Error: unknown option $ARGV[0]\n";
+ exit 1;
+ }
+ shift @ARGV;
+ }
+
+ if ($opt{stat}) {
show_i2c_stats();
exit 0;
}
@@ -6798,14 +6898,21 @@
initialize_dmi_data();
print_dmi_summary();
print "\n";
- print "This program will help you determine which kernel modules you need\n",
- "to load to use lm_sensors most effectively. It is generally safe\n",
- "and recommended to accept the default answers to all questions,\n",
- "unless you know what you're doing.\n\n";
+
+ if ($opt{auto}) {
+ print "Running in automatic mode, default answers to all questions\n",
+ "are assumed.\n\n";
+ } else {
+ print "This program will help you determine which kernel modules you need\n",
+ "to load to use lm_sensors most effectively. It is generally safe\n",
+ "and recommended to accept the default answers to all questions,\n",
+ "unless you know what you're doing.\n\n";
+ }
print "Some south bridges, CPUs or memory controllers contain embedded sensors.\n".
"Do you want to scan for them? This is totally safe. (YES/no): ";
- unless (<STDIN> =~ /^\s*n/i) {
+ $input = read_answer();
+ unless ($input =~ /^\s*n/i) {
# Load the cpuid driver if needed
unless (-e "$sysfs_root/class/cpuid") {
load_module("cpuid");
@@ -6827,7 +6934,8 @@
print "Some Super I/O chips contain embedded sensors. We have to write to\n".
"standard I/O ports to probe them. This is usually safe.\n";
print "Do you want to scan for Super I/O sensors? (YES/no): ";
- unless (<STDIN> =~ /^\s*n/i) {
+ $input = read_answer();
+ unless ($input =~ /^\s*n/i) {
if (initialize_ioports()) {
$superio_features |= scan_superio(0x2e, 0x2f);
$superio_features |= scan_superio(0x4e, 0x4f);
@@ -6843,7 +6951,8 @@
"there, we have to read from arbitrary I/O ports to probe for such\n".
"interfaces. This is normally safe. Do you want to scan for IPMI\n".
"interfaces? (YES/no): ";
- unless (<STDIN> =~ /^\s*n/i) {
+ $input = read_answer();
+ unless ($input =~ /^\s*n/i) {
if (!ipmi_from_smbios()) {
if (initialize_ioports()) {
scan_isa_bus(\@ipmi_ifs);
@@ -6859,7 +6968,7 @@
"safe though. Yes, you do have ISA I/O ports even if you do not have any\n".
"ISA slots! Do you want to scan the ISA I/O ports? (\%s): ",
$superio_features ? "yes/NO" : "YES/no";
- $input = <STDIN>;
+ $input = read_answer();
unless ($input =~ /^\s*n/i
|| ($superio_features && $input !~ /^\s*y/i)) {
if (initialize_ioports()) {
@@ -6876,7 +6985,8 @@
"on some systems.\n".
"Do you want to probe the I2C/SMBus adapters now? (YES/no): ";
- unless (<STDIN> =~ /^\s*n/i) {
+ $input = read_answer();
+ unless ($input =~ /^\s*n/i) {
adapter_pci_detection();
load_module("i2c-dev") unless -e "$sysfs_root/class/i2c-dev";
initialize_i2c_adapters_list();
@@ -6912,9 +7022,11 @@
exit;
}
- print "Now follows a summary of the probes I have just done.\n".
- "Just press ENTER to continue: ";
- <STDIN>;
+ print "\nNow follows a summary of the probes I have just done.\n";
+ unless ($opt{auto}) {
+ print "Just press ENTER to continue: ";
+ <STDIN>;
+ }
initialize_hwmon_autoloaded();
foreach my $driver (keys %chips_detected) {
@@ -6922,6 +7034,7 @@
find_aliases($chips_detected{$driver});
print "\nDriver `$driver'";
print " (autoloaded)" if hwmon_is_autoloaded($driver);
+ print " (built-in)" if is_module_builtin($driver);
print ":\n";
print_chips_report($chips_detected{$driver});
}
@@ -6936,6 +7049,15 @@
}
unload_modules();
+
+ # Check if running non-interactively without --auto
+ if (!$opt{auto} && ! -t STDIN) {
+ print "***************************************************************\n".
+ "Warning: the preferred way to run this script non-interactively\n".
+ "is with option --auto. Other methods are discouraged and may\n".
+ "stop working at some point in the future.\n".
+ "***************************************************************\n\n";
+ }
}
sub cleanup_on_int
|