diff --git a/.cvsignore b/.cvsignore index cf840dc..c5271f1 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1 +1 @@ -lm_sensors-3.1.1.tar.bz2 +lm_sensors-3.1.2.tar.bz2 diff --git a/lm_sensors.spec b/lm_sensors.spec index 0d9345e..e21fae2 100644 --- a/lm_sensors.spec +++ b/lm_sensors.spec @@ -1,13 +1,12 @@ Name: lm_sensors -Version: 3.1.1 -Release: 7%{?dist} +Version: 3.1.2 +Release: 1%{?dist} URL: http://www.lm-sensors.org/ Source: http://dl.lm-sensors.org/lm-sensors/releases/%{name}-%{version}.tar.bz2 Source1: lm_sensors.sysconfig # these 2 were taken from PLD-linux, Thanks! Source2: sensord.sysconfig Source3: sensord.init -Source4: sensors-detect Summary: Hardware monitoring tools Group: Applications/System License: GPLv2+ @@ -83,7 +82,6 @@ mkdir -p $RPM_BUILD_ROOT%{_initrddir} install -p -m 755 prog/init/lm_sensors.init \ $RPM_BUILD_ROOT%{_initrddir}/lm_sensors install -p -m 755 %{SOURCE3} $RPM_BUILD_ROOT%{_initrddir}/sensord -install -p -m 755 %{SOURCE4} $RPM_BUILD_ROOT%{_sbindir}/sensors-detect %clean rm -fr $RPM_BUILD_ROOT @@ -177,6 +175,10 @@ fi %changelog +* Wed Feb 3 2010 Nikola Pajkovsky - 3.1.2-1 +- new upstream release +- drop sensors-detect, beacuse it was taken form svn(531126) + * Thu Dec 17 2009 Nikola Pajkovsky - 3.1.1-7 - Resovles: #226101 - Merge Review: lm_sensors diff --git a/sensors-detect b/sensors-detect deleted file mode 100644 index 249bcca..0000000 --- a/sensors-detect +++ /dev/null @@ -1,5835 +0,0 @@ -#!/usr/bin/perl -w -# -# sensors-detect - Detect hardware monitoring chips -# Copyright (C) 1998 - 2002 Frodo Looijaard -# Copyright (C) 2004 - 2009 Jean Delvare -# -# 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 -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301 USA. -# - -require 5.004; - -use strict; -use Fcntl; -use File::Basename; - -# We will call modprobe, which typically lives in either /sbin, -# /usr/sbin or /usr/local/bin. So make sure these are all in the PATH. -foreach ('/usr/sbin', '/usr/local/sbin', '/sbin') { - $ENV{PATH} = "$_:".$ENV{PATH} - unless $ENV{PATH} =~ m/(^|:)$_\/?(:|$)/; -} - -######################### -# CONSTANT DECLARATIONS # -######################### - -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); - -$revision = '$Revision: 1.1 $ ($Date: 2009/11/10 14:28:19 $)'; -$revision =~ s/\$\w+: (.*?) \$/$1/g; -$revision =~ s/ \([^()]*\)//; - -# This is the list of SMBus or I2C adapters we recognize by their PCI -# signature. This is an easy and fast way to determine which SMBus or I2C -# adapters should be present. -# Each entry must have a vendid (Vendor ID), devid (Device ID) and -# procid (Device name) and driver (Device driver). -@pci_adapters = ( - { - vendid => 0x8086, - devid => 0x7113, - procid => "Intel 82371AB PIIX4 ACPI", - driver => "i2c-piix4", - }, { - vendid => 0x8086, - devid => 0x7603, - procid => "Intel 82372FB PIIX5 ACPI", - driver => "to-be-tested", - }, { - vendid => 0x8086, - devid => 0x719b, - procid => "Intel 82443MX Mobile", - driver => "i2c-piix4", - }, { - vendid => 0x8086, - devid => 0x2413, - procid => "Intel 82801AA ICH", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x2423, - procid => "Intel 82801AB ICH0", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x2443, - procid => "Intel 82801BA ICH2", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x2483, - procid => "Intel 82801CA/CAM ICH3", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x24C3, - procid => "Intel 82801DB ICH4", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x24D3, - procid => "Intel 82801EB ICH5", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x25A4, - procid => "Intel 6300ESB", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x269B, - procid => "Intel Enterprise Southbridge - ESB2", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x266A, - procid => "Intel 82801FB ICH6", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x27DA, - procid => "Intel 82801G ICH7", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x283E, - procid => "Intel 82801H ICH8", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x2930, - procid => "Intel ICH9", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x5032, - procid => "Intel Tolapai", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x3A30, - procid => "Intel ICH10", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x3A60, - procid => "Intel ICH10", - driver => "i2c-i801", - }, { - vendid => 0x8086, - devid => 0x8119, - procid => "Intel SCH", - driver => "i2c-isch", - }, { - vendid => 0x1106, - devid => 0x3040, - procid => "VIA Technologies VT82C586B Apollo ACPI", - driver => "i2c-via", - }, { - vendid => 0x1106, - devid => 0x3050, - procid => "VIA Technologies VT82C596 Apollo ACPI", - driver => "i2c-viapro", - }, { - vendid => 0x1106, - devid => 0x3051, - procid => "VIA Technologies VT82C596B ACPI", - driver => "i2c-viapro", - }, { - vendid => 0x1106, - devid => 0x3057, - procid => "VIA Technologies VT82C686 Apollo ACPI", - driver => "i2c-viapro", - }, { - vendid => 0x1106, - devid => 0x3074, - procid => "VIA Technologies VT8233 VLink South Bridge", - driver => "i2c-viapro", - }, { - vendid => 0x1106, - devid => 0x3147, - procid => "VIA Technologies VT8233A South Bridge", - driver => "i2c-viapro", - }, { - vendid => 0x1106, - devid => 0x3177, - procid => "VIA Technologies VT8233A/8235 South Bridge", - driver => "i2c-viapro", - }, { - vendid => 0x1106, - devid => 0x3227, - procid => "VIA Technologies VT8237 South Bridge", - driver => "i2c-viapro", - }, { - vendid => 0x1106, - devid => 0x3337, - procid => "VIA Technologies VT8237A South Bridge", - driver => "i2c-viapro", - }, { - vendid => 0x1106, - devid => 0x8235, - procid => "VIA Technologies VT8231 South Bridge", - driver => "i2c-viapro", - }, { - vendid => 0x1106, - devid => 0x3287, - procid => "VIA Technologies VT8251 South Bridge", - driver => "i2c-viapro", - }, { - vendid => 0x1106, - devid => 0x8324, - procid => "VIA Technologies CX700 South Bridge", - driver => "i2c-viapro", - }, { - vendid => 0x1106, - devid => 0x8353, - procid => "VIA Technologies VX800/VX820 South Bridge", - driver => "i2c-viapro", - }, { - vendid => 0x1039, - devid => 0x0008, - procid => "Silicon Integrated Systems SIS5595", - driver => "i2c-sis5595", - }, { - vendid => 0x1039, - devid => 0x0630, - procid => "Silicon Integrated Systems SIS630", - driver => "i2c-sis630", - }, { - vendid => 0x1039, - devid => 0x0730, - procid => "Silicon Integrated Systems SIS730", - driver => "i2c-sis630", - }, { - vendid => 0x1039, - devid => 0x0016, - procid => "Silicon Integrated Systems SMBus Controller", - driver => "i2c-sis96x", - }, { - # Both Ali chips below have same PCI ID. Can't be helped. Only one should load. - vendid => 0x10b9, - devid => 0x7101, - procid => "Acer Labs 1533/1543", - driver => "i2c-ali15x3", - }, { - vendid => 0x10b9, - devid => 0x7101, - procid => "Acer Labs 1535", - driver => "i2c-ali1535", - }, { - vendid => 0x10b9, - devid => 0x1563, - procid => "Acer Labs 1563", - driver => "i2c-ali1563", - }, { - vendid => 0x1022, - devid => 0x740b, - procid => "AMD-756 Athlon ACPI", - driver => "i2c-amd756", - }, { - vendid => 0x1022, - devid => 0x7413, - procid => "AMD-766 Athlon ACPI", - driver => "i2c-amd756", - }, { - vendid => 0x1022, - devid => 0x7443, - procid => "AMD-768 System Management", - driver => "i2c-amd756", - }, { - vendid => 0x1022, - devid => 0x746b, - procid => "AMD-8111 ACPI", - driver => "i2c-amd756", - }, { - vendid => 0x1022, - devid => 0x746a, - procid => "AMD-8111 SMBus 2.0", - driver => "i2c-amd8111", - }, { - vendid => 0x10de, - devid => 0x01b4, - procid => "nVidia nForce SMBus", - driver => "i2c-amd756", - }, { - vendid => 0x10de, - devid => 0x0064, - procid => "nVidia Corporation nForce2 SMBus (MCP)", - driver => "i2c-nforce2", - }, { - vendid => 0x10de, - devid => 0x0084, - procid => "nVidia Corporation nForce2 Ultra 400 SMBus (MCP)", - driver => "i2c-nforce2", - }, { - vendid => 0x10de, - devid => 0x00D4, - procid => "nVidia Corporation nForce3 Pro150 SMBus (MCP)", - driver => "i2c-nforce2", - }, { - vendid => 0x10de, - devid => 0x00E4, - procid => "nVidia Corporation nForce3 250Gb SMBus (MCP)", - driver => "i2c-nforce2", - }, { - vendid => 0x10de, - devid => 0x0052, - procid => "nVidia Corporation nForce4 SMBus (MCP)", - driver => "i2c-nforce2", - }, { - vendid => 0x10de, - devid => 0x0034, - procid => "nVidia Corporation nForce4 SMBus (MCP-04)", - driver => "i2c-nforce2", - }, { - vendid => 0x10de, - devid => 0x0264, - procid => "nVidia Corporation nForce SMBus (MCP51)", - driver => "i2c-nforce2", - }, { - vendid => 0x10de, - devid => 0x0368, - procid => "nVidia Corporation nForce SMBus (MCP55)", - driver => "i2c-nforce2", - }, { - vendid => 0x10de, - devid => 0x03eb, - procid => "nVidia Corporation nForce SMBus (MCP61)", - driver => "i2c-nforce2", - }, { - vendid => 0x10de, - devid => 0x0446, - procid => "nVidia Corporation nForce SMBus (MCP65)", - driver => "i2c-nforce2", - }, { - vendid => 0x10de, - devid => 0x0542, - procid => "nVidia Corporation nForce SMBus (MCP67)", - driver => "i2c-nforce2", - }, { - vendid => 0x10de, - devid => 0x07d8, - procid => "nVidia Corporation nForce SMBus (MCP73)", - driver => "i2c-nforce2", - }, { - vendid => 0x10de, - devid => 0x0752, - procid => "nVidia Corporation nForce SMBus (MCP78S)", - driver => "i2c-nforce2", - }, { - vendid => 0x10de, - devid => 0x0aa2, - procid => "nVidia Corporation nForce SMBus (MCP79)", - driver => "i2c-nforce2", - }, { - vendid => 0x1166, - devid => 0x0200, - procid => "ServerWorks OSB4 South Bridge", - driver => "i2c-piix4", - }, { - vendid => 0x1055, - devid => 0x9463, - procid => "SMSC Victory66 South Bridge", - driver => "i2c-piix4", - }, { - vendid => 0x1166, - devid => 0x0201, - procid => "ServerWorks CSB5 South Bridge", - driver => "i2c-piix4", - }, { - vendid => 0x1166, - devid => 0x0203, - procid => "ServerWorks CSB6 South Bridge", - driver => "i2c-piix4", - }, { - vendid => 0x1166, - devid => 0x0205, - procid => "ServerWorks HT-1000 South Bridge", - driver => "i2c-piix4", - }, { - vendid => 0x1002, - devid => 0x4353, - procid => "ATI Technologies Inc ATI SMBus", - driver => "i2c-piix4", - }, { - vendid => 0x1002, - devid => 0x4363, - procid => "ATI Technologies Inc ATI SMBus", - driver => "i2c-piix4", - }, { - vendid => 0x1002, - devid => 0x4372, - procid => "ATI Technologies Inc IXP SB400 SMBus Controller", - driver => "i2c-piix4", - }, { - vendid => 0x1002, - devid => 0x4385, - procid => "ATI Technologies Inc SB600/SB700/SB800 SMBus", - driver => "i2c-piix4", - }, { - vendid => 0x1022, - devid => 0x780b, - procid => "AMD Hudson-2 SMBus", - driver => "i2c-piix4", - }, { - vendid => 0x100B, - devid => 0x0500, - procid => "SCx200 Bridge", - driver => "scx200_acb", - }, { - vendid => 0x100B, - devid => 0x0510, - procid => "SC1100 Bridge", - driver => "scx200_acb", - }, { - vendid => 0x100B, - devid => 0x002B, - procid => "CS5535 ISA bridge", - driver => "scx200_acb", - }, { - vendid => 0x1022, - devid => 0x2090, - procid => "CS5536 [Geode companion] ISA", - driver => "scx200_acb", - } -); - -# Look-up table to find out an I2C bus' driver based on the bus name. -# The match field should contain a regular expression matching the I2C -# bus name as it would appear in sysfs. -# Note that new drivers probably don't need to be added to this table -# if they bind to their device, as we will be able to get the driver name -# from sysfs directly. -use vars qw(@i2c_adapter_names); -@i2c_adapter_names = ( - { driver => "i2c-piix4", match => qr/^SMBus PIIX4 adapter at / }, - { driver => "i2c-i801", match => qr/^SMBus I801 adapter at / }, - { driver => "i2c-via", match => qr/^VIA i2c/ }, - { driver => "i2c-viapro", match => qr/^SMBus V(IA|ia) Pro adapter at / }, - { driver => "i2c-sis5595", match => qr/^SMBus SIS5595 adapter at / }, - { driver => "i2c-sis630", match => qr/^SMBus SIS630 adapter at / }, - { driver => "i2c-sis96x", match => qr/^SiS96x SMBus adapter at / }, - { driver => "i2c-ali15x3", match => qr/^SMBus ALI15X3 adapter at / }, - { driver => "i2c-ali1535", match => qr/^SMBus ALI1535 adapter at/ }, - { driver => "i2c-ali1563", match => qr/^SMBus ALi 1563 Adapter @ / }, - { driver => "i2c-amd756", match => qr/^SMBus (AMD756|AMD766|AMD768|AMD8111|nVidia nForce) adapter at / }, - { driver => "i2c-amd8111", match => qr/^SMBus2 AMD8111 adapter at / }, - { driver => "i2c-nforce2", match => qr/^SMBus nForce2 adapter at / }, - { driver => "scx200_acb", match => qr/^(NatSemi SCx200 ACCESS\.bus|SCx200 ACB\d+|CS553[56] ACB\d+)/ }, -); - -# This is a list of all recognized I2C and ISA chips. -# Each entry must have the following fields: -# name: The full chip name -# driver: The driver name. Put in exactly: -# * "to-be-written" if it is not yet available -# * "use-isa-instead" if no i2c driver will be written -# i2c_addrs (optional): For I2C chips, the list of I2C addresses to -# probe. -# i2c_detect (optional): For I2C chips, the function to call to detect -# this chip. The function will be passed two parameters: an open file -# descriptor to access the bus, and the I2C address to probe. -# isa_addrs (optional): For ISA chips, the list of port addresses to -# probe. -# isa_detect (optional): For ISA chips, the function to call to detect -# this chip. The function will be passed one parameter: the ISA address -# to probe. -# alias_detect (optional): For chips which can be both on the ISA and the -# I2C bus, a function which detects whether two entries are the same. -# The function will be passed three parameters: the ISA address, an -# open file descriptor to access the I2C bus, and the I2C address. -@chip_ids = ( - { - name => "Myson MTP008", - driver => "mtp008", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { mtp008_detect(@_); }, - }, { - name => "National Semiconductor LM78", - driver => "lm78", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { lm78_detect(@_, 0); }, - isa_addrs => [0x290], - isa_detect => sub { lm78_isa_detect(@_, 0); }, - alias_detect => sub { winbond_alias_detect(@_, 0x2b, 0x3d); }, - }, { - name => "National Semiconductor LM79", - driver => "lm78", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { lm78_detect(@_, 2); }, - isa_addrs => [0x290], - isa_detect => sub { lm78_isa_detect(@_, 2); }, - alias_detect => sub { winbond_alias_detect(@_, 0x2b, 0x3d); }, - }, { - name => "National Semiconductor LM75", - driver => "lm75", - i2c_addrs => [0x48..0x4f], - i2c_detect => sub { lm75_detect(@_, 0); }, - }, { - name => "Dallas Semiconductor DS75", - driver => "lm75", - i2c_addrs => [0x48..0x4f], - i2c_detect => sub { lm75_detect(@_, 1); }, - }, { - name => "National Semiconductor LM77", - driver => "lm77", - i2c_addrs => [0x48..0x4b], - i2c_detect => sub { lm77_detect(@_); }, - }, { - name => "National Semiconductor LM80", - driver => "lm80", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { lm80_detect(@_); }, - }, { - name => "National Semiconductor LM85", - driver => "lm85", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm85_detect(@_, 0); }, - }, { - name => "National Semiconductor LM96000 or PC8374L", - driver => "lm85", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm85_detect(@_, 1); }, - }, { - name => "Analog Devices ADM1027", - driver => "lm85", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm85_detect(@_, 2); }, - }, { - name => "Analog Devices ADT7460 or ADT7463", - driver => "lm85", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm85_detect(@_, 3); }, - }, { - name => "SMSC EMC6D100 or EMC6D101", - driver => "lm85", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm85_detect(@_, 4); }, - }, { - name => "SMSC EMC6D102", - driver => "lm85", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm85_detect(@_, 5); }, - }, { - name => "SMSC EMC6D103", - driver => "lm85", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm85_detect(@_, 6); }, - }, { - name => "Winbond WPCD377I", - driver => "not-a-sensor", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm85_detect(@_, 7); }, - }, { - name => "Analog Devices ADT7462", - driver => "adt7462", - i2c_addrs => [0x5c, 0x58], - i2c_detect => sub { adt7467_detect(@_, 2); }, - }, { - name => "Analog Devices ADT7466", - driver => "to-be-written", - i2c_addrs => [0x4c], - i2c_detect => sub { adt7467_detect(@_, 3); }, - }, { - name => "Analog Devices ADT7467 or ADT7468", - driver => "to-be-written", - i2c_addrs => [0x2e], - i2c_detect => sub { adt7467_detect(@_, 0); }, - }, { - name => "Analog Devices ADT7470", - driver => "adt7470", - i2c_addrs => [0x2c, 0x2e, 0x2f], - i2c_detect => sub { adt7467_detect(@_, 4); }, - }, { - name => "Analog Devices ADT7473", - driver => "adt7473", - i2c_addrs => [0x2e], - i2c_detect => sub { adt7473_detect(@_, 0); }, - }, { - name => "Analog Devices ADT7475", - driver => "adt7475", - i2c_addrs => [0x2e], - i2c_detect => sub { adt7473_detect(@_, 1); }, - }, { - name => "Analog Devices ADT7476", - driver => "to-be-written", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adt7467_detect(@_, 1); }, - }, { - name => "Analog Devices ADT7490", - driver => "to-be-written", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adt7490_detect(@_); }, - }, { - name => "Andigilog aSC7511", - driver => "to-be-written", - i2c_addrs => [0x4c], - i2c_detect => sub { andigilog_aSC7511_detect(@_); }, - }, { - name => "Andigilog aSC7512", - driver => "to-be-written", - i2c_addrs => [0x58], - i2c_detect => sub { andigilog_detect(@_, 0); }, - }, { - name => "Andigilog aSC7611", - driver => "to-be-written", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { andigilog_detect(@_, 1); }, - }, { - name => "Andigilog aSC7621", - driver => "to-be-written", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { andigilog_detect(@_, 2); }, - }, { - name => "National Semiconductor LM87", - driver => "lm87", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm87_detect(@_, 0); }, - }, { - name => "Analog Devices ADM1024", - driver => "lm87", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm87_detect(@_, 1); }, - }, { - name => "National Semiconductor LM93", - driver => "lm93", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { lm93_detect(@_); }, - }, { - name => "Winbond W83781D", - driver => "w83781d", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(@_, 0); }, - isa_addrs => [0x290], - isa_detect => sub { w83781d_isa_detect(@_, 0); }, - alias_detect => sub { winbond_alias_detect(@_, 0x2b, 0x3d); }, - }, { - name => "Winbond W83782D", - driver => "w83781d", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(@_, 1); }, - isa_addrs => [0x290], - isa_detect => sub { w83781d_isa_detect(@_, 1); }, - alias_detect => sub { winbond_alias_detect(@_, 0x2b, 0x3d); }, - }, { - name => "Winbond W83783S", - driver => "w83781d", - i2c_addrs => [0x2d], - i2c_detect => sub { w83781d_detect(@_, 2); }, - }, { - name => "Winbond W83791D", - driver => "w83791d", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { w83781d_detect(@_, 7); }, - }, { - name => "Winbond W83792D", - driver => "w83792d", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { w83781d_detect(@_, 8); }, - }, { - name => "Winbond W83793R/G", - driver => "w83793", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { w83793_detect(@_); }, - }, { - name => "Nuvoton W83795G/ADG", - driver => "w83795", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { w83795_detect(@_); }, - }, { - name => "Winbond W83627HF", - driver => "use-isa-instead", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(@_, 3); }, - }, { - name => "Winbond W83627EHF", - driver => "use-isa-instead", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(@_, 9); }, - }, { - name => "Winbond W83627DHG/W83667HG/W83677HG", - driver => "use-isa-instead", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(@_, 10); }, - }, { - name => "Asus AS99127F (rev.1)", - driver => "w83781d", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(@_, 4); }, - }, { - name => "Asus AS99127F (rev.2)", - driver => "w83781d", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(@_, 5); }, - }, { - name => "Asus ASB100 Bach", - driver => "asb100", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { w83781d_detect(@_, 6); }, - }, { - name => "Asus Mozart-2", - driver => "to-be-written", - i2c_addrs => [0x77], - i2c_detect => sub { mozart_detect(@_); }, - }, { - name => "Winbond W83L784R/AR/G", - driver => "to-be-written", - i2c_addrs => [0x2d], - i2c_detect => sub { w83l784r_detect(@_, 0); }, - }, { - name => "Winbond W83L785R/G", - driver => "to-be-written", - i2c_addrs => [0x2d], - i2c_detect => sub { w83l784r_detect(@_, 1); }, - }, { - name => "Winbond W83L786NR/NG/R/G", - driver => "w83l786ng", - i2c_addrs => [0x2e, 0x2f], - i2c_detect => sub { w83l784r_detect(@_, 2); }, - }, { - name => "Winbond W83L785TS-S", - driver => "w83l785ts", - i2c_addrs => [0x2e], - i2c_detect => sub { w83l784r_detect(@_, 3); }, - }, { - name => "Genesys Logic GL518SM", - driver => "gl518sm", - i2c_addrs => [0x2c, 0x2d], - i2c_detect => sub { gl518sm_detect(@_, 0); }, - }, { - name => "Genesys Logic GL520SM", - driver => "gl520sm", - i2c_addrs => [0x2c, 0x2d], - i2c_detect => sub { gl518sm_detect(@_, 1); }, - }, { - name => "Genesys Logic GL525SM", - driver => "to-be-written", - i2c_addrs => [0x2d], - i2c_detect => sub { gl525sm_detect(@_); }, - }, { - name => "Analog Devices ADM9240", - driver => "adm9240", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { adm9240_detect(@_, 0); }, - }, { - name => "Dallas Semiconductor DS1621/DS1631", - driver => "ds1621", - i2c_addrs => [0x48..0x4f], - i2c_detect => sub { ds1621_detect(@_); }, - }, { - name => "Dallas Semiconductor DS1780", - driver => "adm9240", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { adm9240_detect(@_, 1); }, - }, { - name => "National Semiconductor LM81", - driver => "adm9240", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { adm9240_detect(@_, 2); }, - }, { - name => "Analog Devices ADM1026", - driver => "adm1026", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adm1026_detect(@_); }, - }, { - name => "Analog Devices ADM1025", - driver => "adm1025", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adm1025_detect(@_, 0); }, - }, { - name => "Philips NE1619", - driver => "adm1025", - i2c_addrs => [0x2c..0x2d], - i2c_detect => sub { adm1025_detect(@_, 1); }, - }, { - name => "Analog Devices ADM1021", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(@_, 0); }, - }, { - name => "Analog Devices ADM1021A/ADM1023", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(@_, 1); }, - }, { - name => "Maxim MAX1617", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(@_, 2); }, - }, { - name => "Maxim MAX1617A", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(@_, 3); }, - }, { - name => "Maxim MAX1668", - driver => "max1668", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { max1668_detect(@_, 0); }, - }, { - name => "Maxim MAX1805", - driver => "max1668", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { max1668_detect(@_, 1); }, - }, { - name => "Maxim MAX1989", - driver => "max1668", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { max1668_detect(@_, 2); }, - }, { - name => "Maxim MAX6650/MAX6651", - driver => "max6650", - i2c_addrs => [0x1b, 0x1f, 0x48, 0x4b], - i2c_detect => sub { max6650_detect(@_); }, - }, { - name => "Maxim MAX6655/MAX6656", - driver => "max6655", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { max6655_detect(@_); }, - }, { - name => "TI THMC10", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(@_, 4); }, - }, { - name => "National Semiconductor LM84", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(@_, 5); }, - }, { - name => "Genesys Logic GL523SM", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(@_, 6); }, - }, { - name => "Onsemi MC1066", - driver => "adm1021", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { adm1021_detect(@_, 7); }, - }, { - name => "Maxim MAX1618", - driver => "max1619", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { max1619_detect(@_, 1); }, - }, { - name => "Maxim MAX1619", - driver => "max1619", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { max1619_detect(@_, 0); }, - }, { - name => "National Semiconductor LM82/LM83", - driver => "lm83", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { lm83_detect(@_); }, - }, { - name => "National Semiconductor LM90", - driver => "lm90", - i2c_addrs => [0x4c], - i2c_detect => sub { lm90_detect(@_, 0); }, - }, { - name => "National Semiconductor LM89/LM99", - driver => "lm90", - i2c_addrs => [0x4c..0x4d], - i2c_detect => sub { lm90_detect(@_, 1); }, - }, { - name => "National Semiconductor LM86", - driver => "lm90", - i2c_addrs => [0x4c], - i2c_detect => sub { lm90_detect(@_, 2); }, - }, { - name => "Analog Devices ADM1032", - driver => "lm90", - i2c_addrs => [0x4c..0x4d], - i2c_detect => sub { lm90_detect(@_, 3); }, - }, { - name => "Maxim MAX6654/MAX6690", - driver => "to-be-written", # probably lm90 - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { lm90_detect(@_, 4); }, - }, { - name => "Maxim MAX6657/MAX6658/MAX6659", - driver => "lm90", - i2c_addrs => [0x4c], - i2c_detect => sub { max6657_detect(@_); }, - }, { - name => "Maxim MAX6659", - driver => "lm90", - i2c_addrs => [0x4d..0x4e], # 0x4c is handled above - i2c_detect => sub { max6657_detect(@_); }, - }, { - name => "Maxim MAX6646", - driver => "lm90", - i2c_addrs => [0x4d], - i2c_detect => sub { lm90_detect(@_, 6); }, - }, { - name => "Maxim MAX6647", - driver => "lm90", - i2c_addrs => [0x4e], - i2c_detect => sub { lm90_detect(@_, 6); }, - }, { - name => "Maxim MAX6648/MAX6649/MAX6692", - driver => "lm90", - i2c_addrs => [0x4c], - i2c_detect => sub { lm90_detect(@_, 6); }, - }, { - name => "Maxim MAX6680/MAX6681", - driver => "lm90", - i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], - i2c_detect => sub { lm90_detect(@_, 7); }, - }, { - name => "Winbond W83L771W/G", - driver => "lm90", - i2c_addrs => [0x4c], - i2c_detect => sub { lm90_detect(@_, 8); }, - }, { - name => "Texas Instruments TMP401", - driver => "tmp401", - i2c_addrs => [0x4c], - i2c_detect => sub { lm90_detect(@_, 9); }, - }, { - name => "Texas Instruments TMP411", - driver => "tmp401", - i2c_addrs => [0x4c..0x4e], - i2c_detect => sub { lm90_detect(@_, 10); }, - }, { - name => "Texas Instruments TMP421", - driver => "tmp421", - i2c_addrs => [0x2a, 0x4c..0x4f], # 0x1c-0x1f not probed. - i2c_detect => sub { tmp42x_detect(@_, 0); }, - }, { - name => "Texas Instruments TMP422", - driver => "tmp421", - i2c_addrs => [0x4c..0x4f], - i2c_detect => sub { tmp42x_detect(@_, 1); }, - }, { - name => "Texas Instruments TMP423", - driver => "tmp421", - i2c_addrs => [0x4c, 0x4d], - i2c_detect => sub { tmp42x_detect(@_, 2); }, - }, { - name => "National Semiconductor LM95231", - driver => "to-be-written", - i2c_addrs => [0x2b, 0x19, 0x2a], - i2c_detect => sub { lm95231_detect(@_, 0); }, - }, { - name => "National Semiconductor LM95241", - driver => "lm95241", - i2c_addrs => [0x2b, 0x19, 0x2a], - i2c_detect => sub { lm95231_detect(@_, 1); }, - }, { - name => "National Semiconductor LM63", - driver => "lm63", - i2c_addrs => [0x4c], - i2c_detect => sub { lm63_detect(@_, 1); }, - }, { - name => "National Semiconductor LM64", - driver => "to-be-written", # lm63 - i2c_addrs => [0x18, 0x4e], - i2c_detect => sub { lm63_detect(@_, 3); }, - }, { - name => "Fintek F75363SG", - driver => "lm63", # Not yet - i2c_addrs => [0x4c], - i2c_detect => sub { lm63_detect(@_, 2); }, - }, { - name => "National Semiconductor LM73", - driver => "lm73", - i2c_addrs => [0x48..0x4a, 0x4c..0x4e], - i2c_detect => sub { lm73_detect(@_); }, - }, { - name => "National Semiconductor LM92", - driver => "lm92", - i2c_addrs => [0x48..0x4b], - i2c_detect => sub { lm92_detect(@_, 0); }, - }, { - name => "National Semiconductor LM76", - driver => "lm92", - i2c_addrs => [0x48..0x4b], - i2c_detect => sub { lm92_detect(@_, 1); }, - }, { - name => "Maxim MAX6633/MAX6634/MAX6635", - driver => "lm92", - i2c_addrs => [0x48..0x4f], # The MAX6633 can also use 0x40-0x47 but we - # don't want to probe these addresses, it's - # dangerous. - i2c_detect => sub { lm92_detect(@_, 2); }, - }, { - name => "Analog Devices ADT7461", - driver => "lm90", - i2c_addrs => [0x4c..0x4d], - i2c_detect => sub { lm90_detect(@_, 5); }, - }, { - name => "Analog Devices ADT7481", - driver => "to-be-written", - i2c_addrs => [0x4c, 0x4b], - i2c_detect => sub { adt7481_detect(@_); }, - }, { - name => "Analog Devices ADM1029", - driver => "adm1029", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { adm1029_detect(@_); }, - }, { - name => "Analog Devices ADM1030", - driver => "adm1031", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adm1031_detect(@_, 0); }, - }, { - name => "Analog Devices ADM1031", - driver => "adm1031", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adm1031_detect(@_, 1); }, - }, { - name => "Analog Devices ADM1033", - driver => "to-be-written", - i2c_addrs => [0x50..0x53], - i2c_detect => sub { adm1034_detect(@_, 0); }, - }, { - name => "Analog Devices ADM1034", - driver => "to-be-written", - i2c_addrs => [0x50..0x53], - i2c_detect => sub { adm1034_detect(@_, 1); }, - }, { - name => "Analog Devices ADM1022", - driver => "thmc50", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adm1022_detect(@_, 0); }, - }, { - name => "Texas Instruments THMC50", - driver => "thmc50", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { adm1022_detect(@_, 1); }, - }, { - name => "Analog Devices ADM1028", - driver => "thmc50", - i2c_addrs => [0x2e], - i2c_detect => sub { adm1022_detect(@_, 2); }, - }, { - name => "Texas Instruments THMC51", - driver => "to-be-written", # thmc50 - i2c_addrs => [0x2e], # At least (no datasheet) - i2c_detect => sub { adm1022_detect(@_, 3); }, - }, { - name => "VIA VT1211 (I2C)", - driver => "use-isa-instead", - i2c_addrs => [0x2d], - i2c_detect => sub { vt1211_i2c_detect(@_); }, - }, { - name => "ITE IT8712F", - driver => "it87", - i2c_addrs => [0x28..0x2f], - i2c_detect => sub { it8712_i2c_detect(@_); }, - }, { - name => "FSC Poseidon I", - driver => sub { kernel_version_at_least(2, 6, 24) ? "fschmd" : "fscpos" }, - i2c_addrs => [0x73], - i2c_detect => sub { fsc_detect(@_, 0); }, - }, { - name => "FSC Poseidon II", - driver => "to-be-written", - i2c_addrs => [0x73], - i2c_detect => sub { fsc_detect(@_, 1); }, - }, { - name => "FSC Scylla", - driver => "fschmd", - i2c_addrs => [0x73], - i2c_detect => sub { fsc_detect(@_, 2); }, - }, { - name => "FSC Hermes", - driver => sub { kernel_version_at_least(2, 6, 24) ? "fschmd" : "fscher" }, - i2c_addrs => [0x73], - i2c_detect => sub { fsc_detect(@_, 3); }, - }, { - name => "FSC Heimdal", - driver => "fschmd", - i2c_addrs => [0x73], - i2c_detect => sub { fsc_detect(@_, 4); }, - }, { - name => "FSC Heracles", - driver => "fschmd", - i2c_addrs => [0x73], - i2c_detect => sub { fsc_detect(@_, 5); }, - }, { - name => "FSC Hades", - driver => "fschmd", - i2c_addrs => [0x73], - i2c_detect => sub { fsc_detect(@_, 6); }, - }, { - name => "FSC Syleus", - driver => "fschmd", - i2c_addrs => [0x73], - i2c_detect => sub { fsc_detect(@_, 7); }, - }, { - name => "ALi M5879", - driver => "to-be-written", - i2c_addrs => [0x2c..0x2d], - i2c_detect => sub { m5879_detect(@_); }, - }, { - name => "SMSC LPC47M15x/192/292/997", - driver => "smsc47m192", - i2c_addrs => [0x2c..0x2d], - i2c_detect => sub { smsc47m192_detect(@_); }, - }, { - name => "SMSC DME1737", - driver => "dme1737", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { dme1737_detect(@_, 1); }, - }, { - name => "SMSC SCH5027D-NW", - driver => "dme1737", - i2c_addrs => [0x2c..0x2e], - i2c_detect => sub { dme1737_detect(@_, 2); }, - }, { - name => "Fintek F75121R/F75122R/RG (VID+GPIO)", - driver => "to-be-written", - i2c_addrs => [0x4e], # 0x37 not probed - i2c_detect => sub { fintek_detect(@_, 2); }, - }, { - name => "Fintek F75373S/SG", - driver => "f75375s", - i2c_addrs => [0x2d..0x2e], - i2c_detect => sub { fintek_detect(@_, 3); }, - }, { - name => "Fintek F75375S/SP", - driver => "f75375s", - i2c_addrs => [0x2d..0x2e], - i2c_detect => sub { fintek_detect(@_, 4); }, - }, { - name => "Fintek F75387SG/RG", - driver => "to-be-written", - i2c_addrs => [0x2d..0x2e], - i2c_detect => sub { fintek_detect(@_, 5); }, - }, { - name => "Fintek F75383S/M", - driver => "to-be-written", - i2c_addrs => [0x4c], - i2c_detect => sub { fintek_detect(@_, 6); }, - }, { - name => "Fintek F75384S/M", - driver => "to-be-written", - i2c_addrs => [0x4d], - i2c_detect => sub { fintek_detect(@_, 6); }, - }, { - name => "Fintek custom power control IC", - driver => "to-be-written", - i2c_addrs => [0x2f], - i2c_detect => sub { fintek_detect(@_, 7); }, - }, { - name => "Smart Battery", - driver => "sbs", # ACPI driver, not sure if it always works - i2c_addrs => [0x0b], - i2c_detect => sub { smartbatt_detect(@_); }, - } -); - -# IPMI interfaces have their own array now -@ipmi_ifs = ( - { - name => "IPMI BMC KCS", - driver => "ipmisensors", - isa_addrs => [0x0ca0], - isa_detect => sub { ipmi_detect(@_); }, - }, { - name => "IPMI BMC SMIC", - driver => "ipmisensors", - isa_addrs => [0x0ca8], - isa_detect => sub { ipmi_detect(@_); }, - } -); - -# Here is a similar list, but for devices which are not hardware monitoring -# chips. We only list popular devices which happen to live at the same I2C -# address as recognized hardware monitoring chips. The idea is to make it -# clear that the chip in question is of no interest for lm-sensors. -@non_hwmon_chip_ids = ( - { - name => "Winbond W83791SD", - i2c_addrs => [0x2c..0x2f], - i2c_detect => sub { w83791sd_detect(@_); }, - }, { - name => "Fintek F75111R/RG/N (GPIO)", - i2c_addrs => [0x37, 0x4e], - i2c_detect => sub { fintek_detect(@_, 1); }, - }, { - name => "ITE IT8201R/IT8203R/IT8206R/IT8266R", - i2c_addrs => [0x4e], - i2c_detect => sub { ite_overclock_detect(@_); }, - }, { - name => "SPD EEPROM", - i2c_addrs => [0x50..0x57], - i2c_detect => sub { eeprom_detect(@_); }, - }, { - name => "EDID EEPROM", - i2c_addrs => [0x50], - i2c_detect => sub { ddcmonitor_detect(@_); }, - } -); - -# This is a list of all recognized superio chips. -# Each entry must have the following fields: -# name: The full chip name -# driver: The driver name. Put in exactly: -# * "to-be-written" if it is not yet available -# * "not-a-sensor" if the chip doesn't have hardware monitoring -# capabilities (listing such chips here removes the need of manual -# lookup when people report them) -# * "via-smbus-only" if this is a Super-I/O chip whose hardware -# monitoring registers can only be accessed via the SMBus -# devid: The device ID we have to match (base device) -# devid_mask (optional): Bitmask to apply before checking the device ID -# logdev: The logical device containing the sensors -# check (optional): A function to refine the detection. Will be passed -# the index and data ports as parameters. Must return 1 for a matching -# device, 0 otherwise. -# features (optional): Features supported by this device, amongst: -# * FEAT_IN -# * FEAT_FAN -# * FEAT_TEMP -use vars qw(@superio_ids_natsemi @superio_ids_smsc @superio_ids_smsc_ns - @superio_ids_winbond @superio_ids_ite @superio_ids); - -use constant FEAT_IN => (1 << 0); -use constant FEAT_FAN => (1 << 1); -use constant FEAT_TEMP => (1 << 2); -use constant FEAT_SMBUS => (1 << 7); - -@superio_ids_natsemi = ( - { - name => "Nat. Semi. PC8374L Super IO Sensors", # Also Nuvoton WPCD374L - driver => "to-be-written", - devid => 0xf1, - check => sub { - outb($_[0], 0x27); - # Guess work; seen so far: 0x11 - return (inb($_[1]) < 0x80); - }, - logdev => 0x08, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Nuvoton WPCD377I Super IO", # Also WPCD376I - driver => "not-a-sensor", - devid => 0xf1, - check => sub { - outb($_[0], 0x27); - # Guess work; seen so far: 0x91 (twice) - return (inb($_[1]) >= 0x80); - }, - }, { - name => "Nat. Semi. PC87351 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0xe2, - logdev => 0x08, - }, { - name => "Nat. Semi. PC87360 Super IO Fan Sensors", - driver => "pc87360", - devid => 0xe1, - logdev => 0x09, - features => FEAT_FAN, - }, { - name => "Nat. Semi. PC87363 Super IO Fan Sensors", - driver => "pc87360", - devid => 0xe8, - logdev => 0x09, - features => FEAT_FAN, - }, { - name => "Nat. Semi. PC87364 Super IO Fan Sensors", - driver => "pc87360", - devid => 0xe4, - logdev => 0x09, - features => FEAT_FAN, - }, { - name => "Nat. Semi. PC87365 Super IO Fan Sensors", - driver => "pc87360", - devid => 0xe5, - logdev => 0x09, - features => FEAT_FAN, - }, { - name => "Nat. Semi. PC87365 Super IO Voltage Sensors", - driver => "pc87360", - devid => 0xe5, - logdev => 0x0d, - features => FEAT_IN, - }, { - name => "Nat. Semi. PC87365 Super IO Thermal Sensors", - driver => "pc87360", - devid => 0xe5, - logdev => 0x0e, - features => FEAT_TEMP, - }, { - name => "Nat. Semi. PC87366 Super IO Fan Sensors", - driver => "pc87360", - devid => 0xe9, - logdev => 0x09, - features => FEAT_FAN, - }, { - name => "Nat. Semi. PC87366 Super IO Voltage Sensors", - driver => "pc87360", - devid => 0xe9, - logdev => 0x0d, - features => FEAT_IN, - }, { - name => "Nat. Semi. PC87366 Super IO Thermal Sensors", - driver => "pc87360", - devid => 0xe9, - logdev => 0x0e, - features => FEAT_TEMP, - }, { - name => "Nat. Semi. PC87372 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0xf0, - logdev => 0x09, - features => FEAT_FAN, - }, { - name => "Nat. Semi. PC87373 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0xf3, - logdev => 0x09, - features => FEAT_FAN, - }, { - name => "Nat. Semi. PC87591 Super IO", - driver => "to-be-written", - devid => 0xec, - logdev => 0x0f, - }, { - name => "Nat. Semi. PC87317 Super IO", - driver => "not-a-sensor", - devid => 0xd0, - }, { - name => "Nat. Semi. PC97317 Super IO", - driver => "not-a-sensor", - devid => 0xdf, - }, { - name => "Nat. Semi. PC8739x Super IO", - driver => "not-a-sensor", - devid => 0xea, - }, { - name => "Nat. Semi. PC8741x Super IO", - driver => "not-a-sensor", - devid => 0xee, - }, { - name => "Nat. Semi. PC87427 Super IO Fan Sensors", - driver => "pc87427", - devid => 0xf2, - logdev => 0x09, - features => FEAT_FAN, - }, { - name => "Nat. Semi. PC87427 Super IO Health Sensors", - driver => "to-be-written", - devid => 0xf2, - logdev => 0x14, - features => FEAT_IN | FEAT_TEMP, - } -); - -@superio_ids_smsc = ( - { - name => "SMSC DME1737 Super IO", - # Hardware monitoring features are accessed on the SMBus - driver => "via-smbus-only", - devid => 0x78, - }, { - name => "SMSC DME1737 Super IO", - # The DME1737 shows up twice in this list because it can return either - # 0x78 or 0x77 as its device ID. - # Hardware monitoring features are accessed on the SMBus - driver => "via-smbus-only", - devid => 0x77, - }, { - name => "SMSC EMC2700LPC Super IO", - # no datasheet - devid => 0x67, - }, { - name => "SMSC FDC37B72x Super IO", - driver => "not-a-sensor", - devid => 0x4c, - }, { - name => "SMSC FDC37B78x Super IO", - driver => "not-a-sensor", - devid => 0x44, - }, { - name => "SMSC FDC37C672 Super IO", - driver => "not-a-sensor", - devid => 0x40, - }, { - name => "SMSC FDC37M707 Super IO", - driver => "not-a-sensor", - devid => 0x42, - }, { - name => "SMSC FDC37M81x Super IO", - driver => "not-a-sensor", - devid => 0x4d, - }, { - name => "SMSC LPC47B27x Super IO Fan Sensors", - driver => "smsc47m1", - devid => 0x51, - logdev => 0x0a, - features => FEAT_FAN, - }, { - name => "SMSC LPC47B34x Super IO", - driver => "not-a-sensor", - devid => 0x56, - }, { - name => "SMSC LPC47B357/M967 Super IO", - driver => "not-a-sensor", - devid => 0x5d, - }, { - name => "SMSC LPC47B367-NC Super IO", - driver => "not-a-sensor", - devid => 0x6d, - }, { - name => "SMSC LPC47B37x Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x52, - logdev => 0x0a, - features => FEAT_FAN, - }, { - name => "SMSC LPC47B397-NC Super IO", - driver => "smsc47b397", - devid => 0x6f, - logdev => 0x08, - features => FEAT_FAN | FEAT_TEMP, - }, { - name => "SMSC LPC47M10x/112/13x Super IO Fan Sensors", - driver => "smsc47m1", - devid => 0x59, - logdev => 0x0a, - features => FEAT_FAN, - }, { - name => "SMSC LPC47M14x Super IO Fan Sensors", - driver => "smsc47m1", - devid => 0x5f, - logdev => 0x0a, - features => FEAT_FAN, - }, { - name => "SMSC LPC47M15x/192/997 Super IO Fan Sensors", - driver => "smsc47m1", - devid => 0x60, - logdev => 0x0a, - features => FEAT_FAN, - }, { - name => "SMSC LPC47M172 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x14, - logdev => 0x0a, - features => FEAT_FAN, - }, { - name => "SMSC LPC47M182 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x74, - logdev => 0x0a, - features => FEAT_FAN, - }, { - name => "SMSC LPC47M233 Super IO Sensors", - driver => "to-be-written", - devid => 0x6b80, - devid_mask => 0xff80, - logdev => 0x0a, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "SMSC LPC47M292 Super IO Fan Sensors", - driver => "smsc47m1", - devid => 0x6b00, - devid_mask => 0xff80, - logdev => 0x0a, - features => FEAT_FAN, - }, { - name => "SMSC LPC47M584-NC Super IO", - # No datasheet - devid => 0x76, - }, { - name => "SMSC LPC47N252 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x0e, - logdev => 0x09, - features => FEAT_FAN, - }, { - name => "SMSC LPC47S42x Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x57, - logdev => 0x0a, - features => FEAT_FAN, - }, { - name => "SMSC LPC47S45x Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x62, - logdev => 0x0a, - features => FEAT_FAN, - }, { - name => "SMSC LPC47U33x Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x54, - logdev => 0x0a, - features => FEAT_FAN, - }, { - name => "SMSC SCH3112 Super IO", - driver => "dme1737", - devid => 0x7c, - logdev => 0x0a, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "SMSC SCH3114 Super IO", - driver => "dme1737", - devid => 0x7d, - logdev => 0x0a, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "SMSC SCH3116 Super IO", - driver => "dme1737", - devid => 0x7f, - logdev => 0x0a, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "SMSC SCH4307 Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x90, - logdev => 0x08, - features => FEAT_FAN, - }, { - name => "SMSC SCH5027D-NW Super IO", - # Hardware monitoring features are accessed on the SMBus - driver => "via-smbus-only", - devid => 0x89, - }, { - name => "SMSC SCH5127 Super IO", - driver => "dme1737", - devid => 0x86, - logdev => 0x0a, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "SMSC SCH5307-NS Super IO", - driver => "smsc47b397", - devid => 0x81, - logdev => 0x08, - features => FEAT_FAN | FEAT_TEMP, - }, { - name => "SMSC SCH5317 Super IO", - driver => "smsc47b397", - devid => 0x85, - logdev => 0x08, - features => FEAT_FAN | FEAT_TEMP, - }, { - name => "SMSC SCH5317 Super IO", - # The SCH5317 shows up twice in this list because it can return either - # 0x85 or 0x8c as its device ID. - driver => "smsc47b397", - devid => 0x8c, - logdev => 0x08, - features => FEAT_FAN | FEAT_TEMP, - }, { - name => "SMSC SCH5504-NS Super IO", - # No datasheet - driver => "not-a-sensor", - devid => 0x79, - }, { - name => "SMSC SCH5514D-NS Super IO", - # No datasheet - driver => "not-a-sensor", - devid => 0x83, - } -); - -# Non-standard SMSC chip list. These chips differ from the standard ones -# listed above in that the device ID register address is 0x0d instead of -# 0x20 (as specified by the ISA PNP spec). -@superio_ids_smsc_ns = ( - { - name => "SMSC FDC37C665 Super IO", - driver => "not-a-sensor", - devid => 0x65, - }, { - name => "SMSC FDC37C666 Super IO", - driver => "not-a-sensor", - devid => 0x66, - }, { - name => "SMSC FDC37C669 Super IO", - driver => "not-a-sensor", - devid => 0x03, - }, { - name => "SMSC FDC37N769 Super IO", - driver => "not-a-sensor", - devid => 0x28, - }, { - name => "SMSC LPC47N227 Super IO", - driver => "not-a-sensor", - devid => 0x5a, - } -); - -@superio_ids_winbond = ( - { - name => "VIA VT1211 Super IO Sensors", - driver => "vt1211", - devid => 0x3c, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "VIA VT1212 Super IO Lite", # in 100 pin TQFP package - driver => "not-a-sensor", - devid => 0x3e, - }, { - name => "VIA VT1212 Super IO Lite", # in 48 pin LQFP package - driver => "not-a-sensor", - devid => 0x3f, - }, { - name => "Winbond W83627HF/F/HG/G Super IO Sensors", - driver => "w83627hf", - devid => 0x52, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Winbond W83627THF/THG Super IO Sensors", - driver => "w83627hf", - devid => 0x82, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Winbond W83637HF/HG Super IO Sensors", - driver => "w83627hf", - devid => 0x70, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Winbond W83687THF Super IO Sensors", - driver => "w83627hf", - devid => 0x85, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Winbond W83697HF/F/HG Super IO Sensors", - driver => "w83627hf", - devid => 0x60, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Winbond W83697SF/UF/UG Super IO PWM", - driver => "to-be-written", - devid => 0x68, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Winbond W83627EHF/EF/EHG/EG Super IO Sensors", - driver => "w83627ehf", - # W83627EHF datasheet says 0x886x but 0x8853 was seen, thus the - # broader mask. W83627EHG was seen with ID 0x8863. - devid => 0x8840, - devid_mask => 0xFFC0, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Winbond W83627DHG Super IO Sensors", - driver => "w83627ehf", - devid => 0xA020, - devid_mask => 0xFFF0, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Winbond W83627DHG-P Super IO Sensors", - driver => "w83627ehf", - devid => 0xB070, - devid_mask => 0xFFF0, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Winbond W83627UHG Super IO Sensors", - driver => "to-be-written", - devid => 0xA230, - devid_mask => 0xFFF0, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Winbond W83667HG Super IO Sensors", - driver => "w83627ehf", - devid => 0xA510, - devid_mask => 0xFFF0, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Nuvoton W83667HG-B Super IO Sensors", - driver => "to-be-written", # Probably w83627ehf - devid => 0xB350, - devid_mask => 0xFFF0, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Nuvoton W83677HG-I Super IO Sensors", - driver => "to-be-written", # Probably w83627ehf - devid => 0xB470, - devid_mask => 0xFFF0, - logdev => 0x0b, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Winbond W83L517D Super IO", - driver => "not-a-sensor", - devid => 0x61, - }, { - name => "Fintek F71805F/FG Super IO Sensors", - driver => "f71805f", - devid => 0x0406, - logdev => 0x04, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Fintek F71862FG Super IO Sensors", - driver => "f71882fg", - devid => 0x0601, - logdev => 0x04, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Fintek F71869FG Super IO Sensors", - driver => "to-be-written", - devid => 0x0814, - logdev => 0x04, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Fintek F71806FG/F71872FG Super IO Sensors", - driver => "f71805f", - devid => 0x0341, - logdev => 0x04, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Fintek F71858DG Super IO Sensors", - driver => "f71882fg", - devid => 0x0507, - logdev => 0x02, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Fintek F71882FG/F71883FG Super IO Sensors", - driver => "f71882fg", - devid => 0x0541, - logdev => 0x04, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Fintek F71889FG Super IO Sensors", - driver => "f71882fg", - devid => 0x0723, - logdev => 0x04, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "Fintek F81216D Super IO", - driver => "not-a-sensor", - devid => 0x0208, - }, { - name => "Fintek F81218D Super IO", - driver => "not-a-sensor", - devid => 0x0206, - }, { - name => "Asus F8000 Super IO", - driver => "f71882fg", - devid => 0x0581, - logdev => 0x04, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - # Shouldn't be in this family, but seems to be still. - name => "ITE IT8708F Super IO", - driver => "not-a-sensor", - devid => 0x8708, - }, { - # Shouldn't be in this family, but seems to be still. - name => "ITE IT8710F Super IO", - driver => "not-a-sensor", - devid => 0x8710, - } -); - -@superio_ids_ite = ( - { - name => "ITE IT8702F Super IO Fan Sensors", - driver => "to-be-written", - devid => 0x8702, - logdev => 0x04, - features => FEAT_FAN, - }, { - name => "ITE IT8705F Super IO Sensors", - driver => "it87", - devid => 0x8705, - logdev => 0x04, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "ITE IT8712F Super IO Sensors", - driver => "it87", - devid => 0x8712, - logdev => 0x04, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "ITE IT8716F Super IO Sensors", - driver => "it87", - devid => 0x8716, - logdev => 0x04, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "ITE IT8718F Super IO Sensors", - driver => "it87", - devid => 0x8718, - logdev => 0x04, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "ITE IT8720F Super IO Sensors", - driver => "it87", - devid => 0x8720, - logdev => 0x04, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - }, { - name => "ITE IT8726F Super IO Sensors", - driver => "it87", - devid => 0x8726, - logdev => 0x04, - features => FEAT_IN | FEAT_FAN | FEAT_TEMP, - } -); - -# Entries are grouped by family. Each family entry has the following fields: -# family: The family name -# guess (optional): Typical logical device address. This lets us do -# generic probing if we fail to recognize the chip. -# enter: The password sequence to write to the address register -# chips: Array of chips -# The order of families matters, because we stop as soon as one family -# succeeds. So we have to list families with shorter password sequences -# first. -@superio_ids = ( - { - family => "National Semiconductor", - enter => - { - 0x2e => [], - 0x4e => [], - }, - chips => \@superio_ids_natsemi, - }, { - family => "SMSC", - enter => - { - 0x2e => [0x55], - 0x4e => [0x55], - }, - chips => \@superio_ids_smsc, - ns_detect => \&smsc_ns_detect_superio, - ns_chips => \@superio_ids_smsc_ns, - }, { - family => "VIA/Winbond/Nuvoton/Fintek", - guess => 0x290, - enter => - { - 0x2e => [0x87, 0x87], - 0x4e => [0x87, 0x87], - }, - chips => \@superio_ids_winbond, - }, { - family => "ITE", - guess => 0x290, - enter => - { - 0x2e => [0x87, 0x01, 0x55, 0x55], - 0x4e => [0x87, 0x01, 0x55, 0xaa], - }, - chips => \@superio_ids_ite, - } -); - -# Drivers for bridge, CPU and memory embedded sensors -# Each entry must have the following fields: -# name: The device name -# driver: The driver name. Put "to-be-written" if no driver is available. -# detect: Detection callback function. No parameter will be passed to -# this function, it must use global lists of PCI devices, CPU, -# etc. It must return a confidence value, undef if no supported -# CPU is found. -use vars qw(@cpu_ids); - -@cpu_ids = ( - { - name => "Silicon Integrated Systems SIS5595", - driver => "sis5595", - detect => \&sis5595_pci_detect, - }, { - name => "VIA VT82C686 Integrated Sensors", - driver => "via686a", - detect => \&via686a_pci_detect, - }, { - name => "VIA VT8231 Integrated Sensors", - driver => "vt8231", - detect => \&via8231_pci_detect, - }, { - name => "AMD K8 thermal sensors", - driver => "k8temp", - detect => \&k8temp_pci_detect, - }, { - name => "AMD Family 11h thermal sensors", - driver => "to-be-written", - detect => \&fam11h_pci_detect, - }, { - name => "Intel Core family thermal sensor", - driver => "coretemp", - detect => \&coretemp_detect, - }, { - name => "Intel AMB FB-DIMM thermal sensor", - driver => "i5k_amb", - detect => \&intel_amb_detect, - }, { - name => "VIA C7 thermal and voltage sensors", - driver => "c7temp", - detect => \&c7temp_detect, - } -); - -####################### -# AUXILIARY FUNCTIONS # -####################### - -# $_[0] is the sought value -# $_[1..] is the list to seek in -# Returns: 1 if found, 0 if not. -sub contains -{ - my $sought = shift; - local $_; - - foreach (@_) { - return 1 if $sought eq $_; - } - return 0; -} - -# Address can be decimal or hexadecimal -sub valid_address -{ - my $value = shift; - - if ($value !~ m/^(0x[0-9a-f]+|[0-9]+)$/i) { - print "$value is not a valid address, sorry.\n"; - exit -1; - } - $value = oct($value) if $value =~ m/^0x/i; - - return $value; -} - -sub parse_not_to_scan -{ - my ($min, $max, $to_parse) = @_; - my @ranges = split /\s*, \s*/, $to_parse; - my @res; - my $range; - - foreach $range (@ranges) { - my ($start, $end) = split /\s*-\s*/, $range; - $start = valid_address($start); - if (defined $end) { - $end = valid_address($end); - if ($end <= $start) { - print "$start-$end is not a valid range, sorry.\n"; - exit -1; - } - $start = $min if $start < $min; - $end = $max if $end > $max; - push @res, ($start..$end); - } else { - push @res, $start if $start >= $min and $start <= $max; - } - } - - return sort { $a <=> $b } @res; -} - -# $_[0]: Reference to list 1 -# $_[1]: Reference to list 2 -# Result: 0 if they have no elements in common, 1 if they have -# Elements must be numeric. -sub any_list_match -{ - my ($list1, $list2) = @_; - my ($el1, $el2); - - foreach $el1 (@$list1) { - foreach $el2 (@$list2) { - return 1 if $el1 == $el2; - } - } - return 0; -} - -################### -# I/O PORT ACCESS # -################### - -sub initialize_ioports -{ - sysopen(IOPORTS, "/dev/port", O_RDWR) - or die "/dev/port: $!\n"; - binmode(IOPORTS); -} - -sub close_ioports -{ - close(IOPORTS); -} - -# $_[0]: port to read -# Returns: -1 on failure, read value on success. -sub inb -{ - my ($res, $nrchars); - sysseek(IOPORTS, $_[0], 0) or return -1; - $nrchars = sysread(IOPORTS, $res, 1); - return -1 if not defined $nrchars or $nrchars != 1; - $res = unpack("C", $res); - return $res; -} - -# $_[0]: port to write -# $_[1]: value to write -# We assume this can't fail. -sub outb -{ - sysseek(IOPORTS, $_[0], 0); - syswrite(IOPORTS, pack("C", $_[1]), 1); -} - -# $_[0]: Address register -# $_[1]: Data register -# $_[2]: Register to read -# Returns: read value -sub isa_read_byte -{ - outb($_[0], $_[2]); - return inb($_[1]); -} - -# $_[0]: Base address -# $_[1]: Register to read -# Returns: read value -# This one can be used for any ISA chip with index register at -# offset 5 and data register at offset 6. -sub isa_read_i5d6 -{ - my ($addr, $reg) = @_; - return isa_read_byte($addr + 5, $addr + 6, $reg); -} - -################# -# AUTODETECTION # -################# - -use vars qw($dev_i2c $sysfs_root); - -sub initialize_conf -{ - my $use_devfs = 0; - open(local *INPUTFILE, "/proc/mounts") or die "Can't access /proc/mounts!"; - local $_; - while () { - if (m@^\w+ /dev devfs @) { - $use_devfs = 1; - $dev_i2c = '/dev/i2c/'; - } - if (m@^\S+ (/\w+) sysfs @) { - $sysfs_root = $1; - } - } - close(INPUTFILE); - - # We need sysfs for many things - if (!defined $sysfs_root) { - print "Sysfs not mounted?\n"; - exit -1; - } - - my $use_udev = 0; - if (open(*INPUTFILE, '/etc/udev/udev.conf')) { - while () { - next unless m/^\s*udev_db\s*=\s*\"([^"]*)\"/ - || m/^\s*udev_db\s*=\s*(\S+)/; - if (-e $1) { - $use_udev = 1; - $dev_i2c = '/dev/i2c-'; - } - last; - } - close(INPUTFILE); - } - - if (!$use_udev) { - # Try some known default udev db locations, just in case - if (-e '/dev/.udev.tdb' || -e '/dev/.udev' - || -e '/dev/.udevdb') { - $use_udev = 1; - $dev_i2c = '/dev/i2c-'; - } - } - - if (!($use_devfs || $use_udev)) { - if (! -c '/dev/i2c-0' && -x '/sbin/MAKEDEV') { - system("/sbin/MAKEDEV i2c"); - } - if (! -c '/dev/i2c-0' && -x '/dev/MAKEDEV') { - system("/dev/MAKEDEV i2c"); - } - if (-c '/dev/i2c-0') { - $dev_i2c = '/dev/i2c-'; - } else { # default - print "No i2c device files found.\n"; - exit -1; - } - } -} - -# [0] -> VERSION -# [1] -> PATCHLEVEL -# [2] -> SUBLEVEL -# [3] -> EXTRAVERSION -# -use vars qw(@kernel_version $kernel_arch); - -sub initialize_kernel_version -{ - `uname -r` =~ /(\d+)\.(\d+)\.(\d+)(.*)/; - @kernel_version = ($1, $2, $3, $4); - chomp($kernel_arch = `uname -m`); - - # We only support kernels >= 2.6.5 - if (!kernel_version_at_least(2, 6, 5)) { - print "Kernel version is unsupported (too old, >= 2.6.5 needed)\n"; - exit -1; - } -} - -sub kernel_version_at_least -{ - my ($vers, $plvl, $slvl) = @_; - return 1 if ($kernel_version[0] > $vers || - ($kernel_version[0] == $vers && - ($kernel_version[1] > $plvl || - ($kernel_version[1] == $plvl && - ($kernel_version[2] >= $slvl))))); - return 0; -} - -# @cpu is a list of reference to hashes, one hash per CPU. -# Each entry has the following keys: vendor_id, cpu family, model, -# model name and stepping, directly taken from /proc/cpuinfo. -use vars qw(@cpu); - -sub initialize_cpu_list -{ - local $_; - my $entry; - - open(local *INPUTFILE, "/proc/cpuinfo") or die "Can't access /proc/cpuinfo!"; - while () { - if (m/^processor\s*:\s*(\d+)/) { - push @cpu, $entry if scalar keys(%{$entry}); # Previous entry - $entry = {}; # New entry - next; - } - if (m/^(vendor_id|cpu family|model|model name|stepping)\s*:\s*(.+)$/) { - my $k = $1; - my $v = $2; - $v =~ s/\s+/ /g; # Merge multiple spaces - $v =~ s/ $//; # Trim trailing space - $entry->{$k} = $v; - next; - } - } - close(INPUTFILE); - push @cpu, $entry if scalar keys(%{$entry}); # Last entry -} - -# @i2c_adapters is a list of references to hashes, one hash per I2C/SMBus -# adapter present on the system. Each entry has the following keys: path, -# parent, name (directly taken from sysfs), driver and autoload. -use vars qw(@i2c_adapters); - -# Find out whether the driver would be automatically loaded by the modalias -# mechanism. -sub device_driver_autoloads -{ - my $device = shift; - - my $modalias = sysfs_device_attribute($device, "modalias"); - return 0 unless defined($modalias); - - # At the moment we only handle PCI and USB drivers. Other driver - # types, most notably platform and i2c drivers, do not follow the - # device driver model to the letter, and often create their own - # devices. Such drivers appear to be autoloaded when they are not. - return 0 unless $modalias =~ m/^(pci|usb):/; - - my $result = `modprobe -n -v --first-time $modalias 2>&1`; - return ($result =~ m/^insmod/ || - $result =~ m/\balready in kernel\b/); -} - -sub initialize_i2c_adapters_list -{ - my ($entry, $base_dir, $have_i2c_adapter_class); - local $_; - - if (-d "${sysfs_root}/class/i2c-adapter") { - $base_dir = "${sysfs_root}/class/i2c-adapter"; - $have_i2c_adapter_class = 1; - } else { - $base_dir = "${sysfs_root}/bus/i2c/devices"; - $have_i2c_adapter_class = 0; - } - opendir(local *ADAPTERS, $base_dir) or return; - - while (defined($_ = readdir(ADAPTERS))) { - next unless m/^i2c-(\d+)$/; - my $nr = $1; - $entry = {}; # New entry - - # The layout in sysfs has changed over the years - if ($have_i2c_adapter_class) { - my $link = readlink("${base_dir}/i2c-$nr/device"); - if (!defined $link) { - $entry->{path} = "${base_dir}/i2c-$nr"; - $entry->{parent} = "${base_dir}/i2c-$nr"; - } elsif ($link =~ m/^(.*)\/i2c-$nr$/) { - $entry->{path} = "${base_dir}/i2c-$nr/device"; - $entry->{parent} = "${base_dir}/i2c-$nr/$1"; - } else { - $entry->{path} = "${base_dir}/i2c-$nr"; - $entry->{parent} = "$entry->{path}/device"; - } - } else { - my $link = readlink("${base_dir}/i2c-$nr"); - $link =~ s/\/i2c-$nr$//; - $entry->{path} = "${base_dir}/i2c-$nr"; - $entry->{parent} = "${base_dir}/$link"; - } - - $entry->{name} = sysfs_device_attribute($entry->{path}, "name"); - next if $entry->{name} eq "ISA main adapter"; - - # 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}) - || find_i2c_adapter_driver($entry->{name}) - || 'UNKNOWN'; - - $entry->{autoload} = device_driver_autoloads($entry->{parent}); - $i2c_adapters[$nr] = $entry; - } - closedir(ADAPTERS); -} - -# %hwmon_autoloaded is a list of hwmon drivers which are autoloaded -# (typically by udev.) We don't need to load these drivers ourselves. -use vars qw(%hwmon_autoloaded); - -sub initialize_hwmon_autoloaded -{ - my $class_dir = "${sysfs_root}/class/hwmon"; - opendir(local *HWMON, $class_dir) or return; - - my ($hwmon, $driver); - while (defined($hwmon = readdir(HWMON))) { - next unless $hwmon =~ m/^hwmon\d+$/; - - $driver = sysfs_device_driver("${class_dir}/$hwmon/device"); - next unless defined($driver); - - if (device_driver_autoloads("${class_dir}/$hwmon/device")) { - $driver =~ tr/-/_/; - $hwmon_autoloaded{$driver}++ - } - } - closedir(HWMON); -} - -sub hwmon_is_autoloaded -{ - my $driver = shift; - $driver =~ tr/-/_/; - return exists($hwmon_autoloaded{$driver}); -} - -########### -# MODULES # -########### - -use vars qw(%modules_list %modules_supported @modules_we_loaded); - -sub initialize_modules_list -{ - local $_; - - open(local *INPUTFILE, "/proc/modules") or return; - while () { - tr/-/_/; # Probably not needed - $modules_list{$1} = 1 if m/^(\S*)/; - } -} - -sub is_module_loaded -{ - my $module = shift; - $module =~ tr/-/_/; - return exists $modules_list{$module} -} - -sub load_module -{ - my $module = shift; - - return if is_module_loaded($module); - - system("modprobe", $module); - if (($? >> 8) != 0) { - print "Failed to load module $module.\n"; - return -1; - } - - print "Module $module loaded successfully.\n"; - push @modules_we_loaded, $module; - - # Update the list of loaded modules - my $normalized = $module; - $normalized =~ tr/-/_/; - $modules_list{$normalized} = 1; -} - -sub initialize_modules_supported -{ - foreach my $chip (@chip_ids) { - next if $chip->{driver} eq "to-be-written"; - next if $chip->{driver} eq "use-isa-instead"; - - my $normalized = $chip->{driver}; - $normalized =~ tr/-/_/; - $modules_supported{$normalized}++; - } -} - -sub unload_modules -{ - return unless @modules_we_loaded; - - # Attempt to unload all kernel drivers we loaded ourselves - while (my $module = pop @modules_we_loaded) { - print "Unloading $module... "; - system("modprobe -r $module 2> /dev/null"); - if (($? >> 8) == 0) { - print "OK\n"; - } else { - print "failed\n"; - } - } - print "\n"; -} - -############ -# DMI DATA # -############ - -use vars qw(%dmi $dmidecode_ok); - -# Returns: 1 if dmidecode is recent enough, 0 if not -# Cache the result in case it is needed again later. -sub check_dmidecode_version -{ - return $dmidecode_ok if defined $dmidecode_ok; - - my $version; - if (open(local *DMIDECODE, "dmidecode --version 2>/dev/null |")) { - $version = ; - close(DMIDECODE); - chomp $version if defined $version; - } - - if (!defined $version - || !($version =~ m/^(\d+).(\d+)$/) - || !(($1 == 2 && $2 >= 7) || $1 > 2)) { - print "# DMI data unavailable, please consider installing dmidecode 2.7\n". - "# or later for better results.\n"; - $dmidecode_ok = 0; - } else { - $dmidecode_ok = 1; - } - - return $dmidecode_ok; -} - -sub initialize_dmi_data -{ - my %items = ( - # sysfs file name => dmidecode string name - sys_vendor => 'system-manufacturer', - product_name => 'system-product-name', - product_version => 'system-version', - board_vendor => 'baseboard-manufacturer', - board_name => 'baseboard-product-name', - board_version => 'baseboard-product-name', - chassis_type => 'chassis-type', - ); - # Many BIOS have broken DMI data, filter it out - my %fake = ( - 'System Manufacturer' => 1, - 'System Name' => 1, - ); - my $dmi_id_dir; - - # First try reading the strings from sysfs if available - if (-d ($dmi_id_dir = "$sysfs_root/devices/virtual/dmi/id") # kernel >= 2.6.28 - || -d ($dmi_id_dir = "$sysfs_root/class/dmi/id")) { - foreach my $k (keys %items) { - $dmi{$k} = sysfs_device_attribute($dmi_id_dir, $k); - } - } else { - # Else fallback on calling dmidecode - return unless check_dmidecode_version(); - - foreach my $k (keys %items) { - next unless open(local *DMIDECODE, - "dmidecode -s $items{$k} 2>/dev/null |"); - $dmi{$k} = ; - close(DMIDECODE); - } - } - - # Strip trailing white-space, discard empty field - foreach my $k (keys %dmi) { - if (!defined $dmi{$k}) { - delete $dmi{$k}; - next; - } - $dmi{$k} =~ s/\s*$//; - delete $dmi{$k} if $dmi{$k} eq '' || exists $fake{$dmi{$k}}; - } -} - -sub print_dmi_summary -{ - my ($system, $board); - if (defined $dmi{sys_vendor} && defined $dmi{product_name}) { - $system = "$dmi{sys_vendor} $dmi{product_name}"; - } - if (defined $dmi{board_vendor} && defined $dmi{board_name}) { - $board = "$dmi{board_vendor} $dmi{board_name}"; - } - - if (defined $system) { - print "# System: $system"; - print " (laptop)" if (is_laptop()); - print "\n"; - } - print "# Board: $board\n" if defined $board - && (!defined $system || $system ne $board); -} - -sub dmi_match -{ - my $key = shift; - my $value; - - return unless defined $dmi{$key}; - while (defined ($value = shift)) { - return 1 if $dmi{$key} =~ m/\b$value\b/i; - } - return 0; -} - -sub is_laptop -{ - return 0 unless $dmi{chassis_type}; - return 1 if $dmi{chassis_type} =~ m/(Laptop|Notebook|Hand Held)/i; - return 1 if $dmi{chassis_type} =~ m/^(9|10|11|14)$/; - return 0; -} - -################# -# SYSFS HELPERS # -################# - -# From a sysfs device path, return the driver (module) name, or undef -sub sysfs_device_driver -{ - my $device = shift; - - my $link = readlink("$device/driver/module"); - return unless defined $link; - return basename($link); -} - -# From a sysfs device path, return the subsystem name, or undef -sub sysfs_device_subsystem -{ - my $device = shift; - - my $link = readlink("$device/subsystem"); - return unless defined $link; - return basename($link); -} - -# From a sysfs device path and an attribute name, return the attribute -# value, or undef -sub sysfs_device_attribute -{ - my ($device, $attr) = @_; - my $value; - - open(local *FILE, "$device/$attr") or return; - $value = ; - close(FILE); - return unless defined $value; - - chomp($value); - return $value; -} - -############## -# PCI ACCESS # -############## - -use vars qw(%pci_list); - -# This function returns a list of hashes. Each hash has some PCI information: -# 'domain', 'bus', 'slot' and 'func' uniquely identify a PCI device in a -# computer; 'vendid' and 'devid' uniquely identify a type of device. -# 'class' lets us spot unknown SMBus adapters. -sub read_sys_dev_pci -{ - my $devices = shift; - my ($dev, @pci_list); - - opendir(local *DEVICES, "$devices") - or die "$devices: $!"; - - while (defined($dev = readdir(DEVICES))) { - my %record; - next unless $dev =~ - m/^(?:([\da-f]+):)?([\da-f]+):([\da-f]+)\.([\da-f]+)$/; - - $record{domain} = hex $1; - $record{bus} = hex $2; - $record{slot} = hex $3; - $record{func} = hex $4; - - $record{vendid} = oct sysfs_device_attribute("$devices/$dev", - "vendor"); - $record{devid} = oct sysfs_device_attribute("$devices/$dev", - "device"); - $record{class} = (oct sysfs_device_attribute("$devices/$dev", - "class")) >> 8; - - push @pci_list, \%record; - } - - return \@pci_list; -} - -sub initialize_pci -{ - my $pci_list; - local $_; - - $pci_list = read_sys_dev_pci("$sysfs_root/bus/pci/devices"); - - # Note that we lose duplicate devices at this point, but we don't - # really care. What matters to us is which unique devices are present, - # not how many of each. - %pci_list = map { - sprintf("%04x:%04x", $_->{vendid}, $_->{devid}) => $_ - } @{$pci_list}; -} - -##################### -# ADAPTER DETECTION # -##################### - -# Build and return a PCI device's bus ID -sub pci_busid -{ - my $device = shift; - my $busid; - - $busid = sprintf("\%02x:\%02x.\%x", - $device->{bus}, $device->{slot}, $device->{func}); - $busid = sprintf("\%04x:", $device->{domain}) . $busid - if defined $device->{domain}; - - return $busid; -} - -sub adapter_pci_detection -{ - my ($key, $device, $try, %smbus, $count); - - # Build a list of detected SMBus devices - foreach $key (keys %pci_list) { - $device = $pci_list{$key}; - $smbus{$key}++ - if exists $device->{class} && - ($device->{class} == 0x0c01 || # Access Bus - $device->{class} == 0x0c05); # SMBus - } - - # Loop over the known I2C/SMBus adapters - foreach $try (@pci_adapters) { - $key = sprintf("%04x:%04x", $try->{vendid}, $try->{devid}); - next unless exists $pci_list{$key}; - - $device = $pci_list{$key}; - if ($try->{driver} eq "to-be-tested") { - print "\nWe are currently looking for testers for this adapter!\n". - "Please check http://www.lm-sensors.org/wiki/Devices\n". - "and/or contact us if you want to help.\n\n". - "Continue... "; - ; - print "\n"; - } - - if ($try->{driver} =~ m/^to-be-/) { - printf "No known driver for device \%s: \%s\n", - pci_busid($device), $try->{procid}; - } else { - printf "Using driver `\%s' for device \%s: \%s\n", - $try->{driver}, pci_busid($device), - $try->{procid}; - $count++; - load_module($try->{driver}); - } - - # Delete from detected SMBus device list - delete $smbus{$key}; - } - - # Now see if there are unknown SMBus devices left - foreach $key (keys %smbus) { - $device = $pci_list{$key}; - printf "Found unknown SMBus adapter \%04x:\%04x at \%s.\n", - $device->{vendid}, $device->{devid}, pci_busid($device); - } - - print "Sorry, no supported PCI bus adapters found.\n" - unless $count; -} - -# $_[0]: Adapter description as found in sysfs -sub find_i2c_adapter_driver -{ - my $name = shift; - my $entry; - - foreach $entry (@i2c_adapter_names) { - return $entry->{driver} - if $name =~ $entry->{match}; - } -} - -############################# -# I2C AND SMBUS /DEV ACCESS # -############################# - -# This should really go into a separate module/package. - -# These are copied from - -use constant IOCTL_I2C_SLAVE => 0x0703; -use constant IOCTL_I2C_FUNCS => 0x0705; -use constant IOCTL_I2C_SMBUS => 0x0720; - -use constant SMBUS_READ => 1; -use constant SMBUS_WRITE => 0; - -use constant SMBUS_QUICK => 0; -use constant SMBUS_BYTE => 1; -use constant SMBUS_BYTE_DATA => 2; -use constant SMBUS_WORD_DATA => 3; - -use constant I2C_FUNC_SMBUS_QUICK => 0x00010000; -use constant I2C_FUNC_SMBUS_READ_BYTE => 0x00020000; -use constant I2C_FUNC_SMBUS_READ_BYTE_DATA => 0x00080000; - -# Get the i2c adapter's functionalities -# $_[0]: Reference to an opened filehandle -# Returns: -1 on failure, functionality bitfield on success. -sub i2c_get_funcs -{ - my $file = shift; - my $funcs = pack("L", 0); # Allocate space - - ioctl($file, IOCTL_I2C_FUNCS, $funcs) or return -1; - $funcs = unpack("L", $funcs); - - return $funcs; -} - -# Select the device to communicate with through its address. -# $_[0]: Reference to an opened filehandle -# $_[1]: Address to select -# Returns: 0 on failure, 1 on success. -sub i2c_set_slave_addr -{ - my ($file, $addr) = @_; - - # Reset register data cache - @i2c_byte_cache = (); - - $addr += 0; # Make sure it's a number not a string - ioctl($file, IOCTL_I2C_SLAVE, $addr) or return 0; - return 1; -} - -# i2c_smbus_access is based upon the corresponding C function (see -# ). You should not need to call this directly. -# $_[0]: Reference to an opened filehandle -# $_[1]: SMBUS_READ for reading, SMBUS_WRITE for writing -# $_[2]: Command (usually register number) -# $_[3]: Transaction kind (SMBUS_BYTE, SMBUS_BYTE_DATA, etc.) -# $_[4]: Reference to an array used for input/output of data -# Returns: 0 on failure, 1 on success. -# Note that we need to get back to Integer boundaries through the 'x2' -# in the pack. This is very compiler-dependent; I wish there was some other -# way to do this. -sub i2c_smbus_access -{ - my ($file, $read_write, $command, $size, $data) = @_; - my $data_array = pack("C32", @$data); - my $ioctl_data = pack("C2x2Ip", $read_write, $command, $size, - $data_array); - - ioctl($file, IOCTL_I2C_SMBUS, $ioctl_data) or return 0; - @{$_[4]} = unpack("C32", $data_array); - return 1; -} - -# $_[0]: Reference to an opened filehandle -# Returns: -1 on failure, the read byte on success. -sub i2c_smbus_read_byte -{ - my ($file) = @_; - my @data; - - i2c_smbus_access($file, SMBUS_READ, 0, SMBUS_BYTE, \@data) - or return -1; - return $data[0]; -} - -# $_[0]: Reference to an opened filehandle -# $_[1]: Command byte (usually register number) -# Returns: -1 on failure, the read byte on success. -# Read byte data values are cached by default. As we keep reading the -# same registers over and over again in the detection functions, and -# SMBus can be slow, caching results in a big performance boost. -sub i2c_smbus_read_byte_data -{ - my ($file, $command, $nocache) = @_; - my @data; - - return $i2c_byte_cache[$command] - if !$nocache && exists $i2c_byte_cache[$command]; - - i2c_smbus_access($file, SMBUS_READ, $command, SMBUS_BYTE_DATA, \@data) - or return -1; - return ($i2c_byte_cache[$command] = $data[0]); -} - -# $_[0]: Reference to an opened filehandle -# $_[1]: Command byte (usually register number) -# Returns: -1 on failure, the read word on success. -# Use this function with care, some devices don't like word reads, -# so you should do as much of the detection as possible using byte reads, -# and only start using word reads when there is a good chance that -# the detection will succeed. -# Note: some devices use the wrong endianness. -sub i2c_smbus_read_word_data -{ - my ($file, $command) = @_; - my @data; - i2c_smbus_access($file, SMBUS_READ, $command, SMBUS_WORD_DATA, \@data) - or return -1; - return $data[0] + 256 * $data[1]; -} - -# $_[0]: Reference to an opened filehandle -# $_[1]: Address -# $_[2]: Functionalities of this i2c adapter -# Returns: 1 on successful probing, 0 else. -# This function is meant to prevent AT24RF08 corruption and write-only -# chips locks. This is done by choosing the best probing method depending -# on the address range. -sub i2c_probe -{ - my ($file, $addr, $funcs) = @_; - - if (($addr >= 0x50 && $addr <= 0x5F) - || ($addr >= 0x30 && $addr <= 0x37)) { - # This covers all EEPROMs we know of, including page protection - # addresses. Note that some page protection addresses will not - # reveal themselves with this, because they ack on write only, - # but this is probably better since some EEPROMs write-protect - # themselves permanently on almost any write to their page - # protection address. - return 0 unless ($funcs & I2C_FUNC_SMBUS_READ_BYTE); - return i2c_smbus_access($file, SMBUS_READ, 0, SMBUS_BYTE, []); - } elsif ($addr == 0x73) { - # Special case for FSC chips, as at least the Syleus locks - # up with our regular probe code. Note that to our current - # knowledge only FSC chips live on this address, and for them - # this probe method is safe. - return 0 unless ($funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA); - return i2c_smbus_access($file, SMBUS_READ, 0, SMBUS_BYTE_DATA, []); - } else { - return 0 unless ($funcs & I2C_FUNC_SMBUS_QUICK); - return i2c_smbus_access($file, SMBUS_WRITE, 0, SMBUS_QUICK, []); - } -} - -# $_[0]: Reference to an opened file handle -# Returns: 1 if the device is safe to access, 0 else. -# This function is meant to prevent access to 1-register-only devices, -# which are designed to be accessed with SMBus receive byte and SMBus send -# byte transactions (i.e. short reads and short writes) and treat SMBus -# read byte as a real write followed by a read. The device detection -# routines would write random values to the chip with possibly very nasty -# results for the hardware. Note that this function won't catch all such -# chips, as it assumes that reads and writes relate to the same register, -# but that's the best we can do. -sub i2c_safety_check -{ - my ($file) = @_; - my $data; - - # First we receive a byte from the chip, and remember it. - $data = i2c_smbus_read_byte($file); - return 1 if ($data < 0); - - # We receive a byte again; very likely to be the same for - # 1-register-only devices. - return 1 if (i2c_smbus_read_byte($file) != $data); - - # Then we try a standard byte read, with a register offset equal to - # the byte we received; we should receive the same byte value in return. - return 1 if (i2c_smbus_read_byte_data($file, $data) != $data); - - # Then we try a standard byte read, with a slightly different register - # offset; we should again receive the same byte value in return. - return 1 if (i2c_smbus_read_byte_data($file, $data ^ 1) != ($data ^ 1)); - - # Apprently this is a 1-register-only device, restore the original - # register value and leave it alone. - i2c_smbus_read_byte_data($file, $data); - return 0; -} - -#################### -# ADAPTER SCANNING # -#################### - -use vars qw(%chips_detected); - -# We will build a complicated structure %chips_detected here, being a hash -# where keys are driver names and values are detected chip information in -# the form of a list of hashes of type 'detect_data'. - -# Type detect_data: -# A hash -# with field 'i2c_devnr', contianing the /dev/i2c-* number of this -# adapter (if this is an I2C detection) -# with field 'i2c_addr', containing the I2C address of the detection; -# (if this is an I2C detection) -# with field 'i2c_sub_addrs', containing a reference to a list of -# other I2C addresses (if this is an I2C detection) -# with field 'isa_addr' containing the ISA address this chip is on -# (if this is an ISA detection) -# with field 'conf', containing the confidence level of this detection -# with field 'chipname', containing the chip name -# with optional field 'alias_detect', containing a reference to an alias -# detection function for this chip - -# This adds a detection to the above structure. -# Not all possibilities of i2c_addr and i2c_sub_addrs are exhausted. -# In all normal cases, it should be all right. -# $_[0]: chip driver -# $_[1]: reference to data hash -# Returns: Nothing -sub add_i2c_to_chips_detected -{ - my ($chipdriver, $datahash) = @_; - my ($i, $new_detected_ref, $detected_ref, $detected_entry, - $put_in_detected, @hash_addrs, @entry_addrs); - - # First determine where the hash has to be added. - $chips_detected{$chipdriver} = [] - unless exists $chips_detected{$chipdriver}; - $new_detected_ref = $chips_detected{$chipdriver}; - - # Find out whether our new entry should go into the detected list - # or not. We compare all i2c addresses; if at least one matches, - # but our confidence value is lower, we assume this is a misdetection, - # in which case we simply discard our new entry. - @hash_addrs = ($datahash->{i2c_addr}); - push @hash_addrs, @{$datahash->{i2c_sub_addrs}} - if exists $datahash->{i2c_sub_addrs}; - $put_in_detected = 1; - FIND_LOOP: - foreach $detected_ref (values %chips_detected) { - foreach $detected_entry (@{$detected_ref}) { - next unless defined $detected_entry->{i2c_addr}; - @entry_addrs = ($detected_entry->{i2c_addr}); - push @entry_addrs, @{$detected_entry->{i2c_sub_addrs}} - if exists $detected_entry->{i2c_sub_addrs}; - if ($detected_entry->{i2c_devnr} == $datahash->{i2c_devnr} && - any_list_match(\@entry_addrs, \@hash_addrs)) { - if ($detected_entry->{conf} >= $datahash->{conf}) { - $put_in_detected = 0; - } - last FIND_LOOP; - } - } - } - - return unless $put_in_detected; - - # Here, we discard all entries which match at least in one main or - # sub address. This may not be the best idea to do, as it may remove - # detections without replacing them with second-best ones. Too bad. - foreach $detected_ref (values %chips_detected) { - for ($i = @$detected_ref-1; $i >=0; $i--) { - next unless defined $detected_ref->[$i]->{i2c_addr}; - @entry_addrs = ($detected_ref->[$i]->{i2c_addr}); - push @entry_addrs, @{$detected_ref->[$i]->{i2c_sub_addrs}} - if exists $detected_ref->[$i]->{i2c_sub_addrs}; - if ($detected_ref->[$i]->{i2c_devnr} == $datahash->{i2c_devnr} && - any_list_match(\@entry_addrs, \@hash_addrs)) { - splice @$detected_ref, $i, 1; - } - } - } - - # Now add the new entry to detected - push @$new_detected_ref, $datahash; -} - -# This adds a detection to the above structure. -# $_[0]: chip driver -# $_[1]: reference to data hash -sub add_isa_to_chips_detected -{ - my ($chipdriver, $datahash) = @_; - my ($i, $new_detected_ref, $detected_ref); - - # First determine where the hash has to be added. - $chips_detected{$chipdriver} = [] - unless exists $chips_detected{$chipdriver}; - $new_detected_ref = $chips_detected{$chipdriver}; - - # Find out whether our new entry should go into the detected list - # or not. We only compare main isa_addr here, of course. - foreach $detected_ref (values %chips_detected) { - for ($i = 0; $i < @{$detected_ref}; $i++) { - if (exists $detected_ref->[$i]->{isa_addr} and - exists $datahash->{isa_addr} and - $detected_ref->[$i]->{isa_addr} == $datahash->{isa_addr}) { - if ($detected_ref->[$i]->{conf} < $datahash->{conf}) { - splice @$detected_ref, $i, 1; - push @$new_detected_ref, $datahash; - } - return; - } - } - } - - # Not found? OK, put it in the detected list - push @$new_detected_ref, $datahash; -} - -# $_[0]: reference to an array of chips which may be aliases of each other -sub find_aliases -{ - my $detected = shift; - my ($isa, $i2c, $dev, $alias_detect, $is_alias); - - for ($isa = 0; $isa < @{$detected}; $isa++) { - # Look for chips with an ISA address but no I2C address - next unless defined $detected->[$isa]; - next unless $detected->[$isa]->{isa_addr}; - next if defined $detected->[$isa]->{i2c_addr}; - # Additionally, the chip must possibly have I2C aliases - next unless defined $detected->[$isa]->{alias_detect}; - - for ($i2c = 0; $i2c < @{$detected}; $i2c++) { - # Look for chips with an I2C address but no ISA address - next unless defined $detected->[$i2c]; - next unless defined $detected->[$i2c]->{i2c_addr}; - next if $detected->[$i2c]->{isa_addr}; - # Additionally, it must have the same chip name - next unless $detected->[$i2c]->{chipname} eq - $detected->[$isa]->{chipname}; - - # We have potential aliases, check if they actually are - $dev = $dev_i2c.$detected->[$i2c]->{i2c_devnr}; - open(local *FILE, $dev) or - print("Can't open $dev\n"), - next; - binmode(FILE); - i2c_set_slave_addr(\*FILE, $detected->[$i2c]->{i2c_addr}) or - print("Can't set I2C address for $dev\n"), - next; - - initialize_ioports(); - $alias_detect = $detected->[$isa]->{alias_detect}; - $is_alias = &$alias_detect($detected->[$isa]->{isa_addr}, - \*FILE, - $detected->[$i2c]->{i2c_addr}); - close(FILE); - close_ioports(); - - next unless $is_alias; - # This is an alias: copy the I2C data into the ISA - # entry, then discard the I2C entry - $detected->[$isa]->{i2c_devnr} = $detected->[$i2c]->{i2c_devnr}; - $detected->[$isa]->{i2c_addr} = $detected->[$i2c]->{i2c_addr}; - $detected->[$isa]->{i2c_sub_addr} = $detected->[$i2c]->{i2c_sub_addr}; - undef $detected->[$i2c]; - last; - } - } - - # The loops above may have made the chip list sparse, make it - # compact again - for ($isa = 0; $isa < @{$detected}; ) { - if (defined($detected->[$isa])) { - $isa++; - } else { - splice @{$detected}, $isa, 1; - } - } -} - -# From the list of known I2C/SMBus devices, build a list of I2C addresses -# which are worth probing. There's no point in probing an address for which -# we don't know a single device, and probing some addresses has caused -# random trouble in the past. -sub i2c_addresses_to_scan -{ - my @used; - my @addresses; - my $addr; - - foreach my $chip (@chip_ids) { - next unless defined $chip->{i2c_addrs}; - foreach $addr (@{$chip->{i2c_addrs}}) { - $used[$addr]++; - } - } - - for ($addr = 0x03; $addr <= 0x77; $addr++) { - push @addresses, $addr if $used[$addr]; - } - return \@addresses; -} - -# $_[0]: The number of the adapter to scan -# $_[1]: Address -sub add_busy_i2c_address -{ - my ($adapter_nr, $addr) = @_; - # 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); - - $device = sprintf("$sysfs_root/bus/i2c/devices/\%d-\%04x", - $adapter_nr, $addr); - $driver = sysfs_device_driver($device); - - if (!defined($driver)) { - printf("Client at address 0x%02x can not be probed - ". - "unload all client drivers first!\n", $addr); - return; - } - - $new_hash = { - conf => 6, # Arbitrary confidence - i2c_addr => $addr, - chipname => sysfs_device_attribute($device, "name") - || "unknown", - i2c_devnr => $adapter_nr, - }; - - printf "Client found at address 0x\%02x\n", $addr; - printf "Handled by driver `\%s' (already loaded), chip type `\%s'\n", - $driver, $new_hash->{chipname}; - - # 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); - } else { - print " (note: this is probably NOT a sensor chip!)\n"; - } -} - -# $_[0]: The number of the adapter to scan -# $_[1]: Address -# $_[2]: Chip being probed -sub probe_free_i2c_address -{ - my ($adapter_nr, $addr, $chip) = @_; - my ($conf, @other_addr, $new_hash); - - printf("\%-60s", sprintf("Probing for `\%s'... ", $chip->{name})); - if (($conf, @other_addr) = &{$chip->{i2c_detect}} (\*FILE, $addr)) { - if ($chip->{driver} eq "not-a-sensor") { - print "Yes\n", - " (confidence $conf, not a hardware monitoring chip"; - } else { - print "Success!\n", - " (confidence $conf, driver `$chip->{driver}'"; - } - if (@other_addr) { - print ", other addresses:"; - @other_addr = sort @other_addr; - foreach my $other_addr (@other_addr) { - printf(" 0x%02x", $other_addr); - } - } - print ")\n"; - - return if ($chip->{driver} eq "not-a-sensor" - || $chip->{driver} eq "use-isa-instead"); - - $new_hash = { - conf => $conf, - i2c_addr => $addr, - chipname => $chip->{name}, - i2c_devnr => $adapter_nr, - }; - if (@other_addr) { - my @other_addr_copy = @other_addr; - $new_hash->{i2c_sub_addrs} = \@other_addr_copy; - } - add_i2c_to_chips_detected($chip->{driver}, $new_hash); - } else { - print "No\n"; - } -} - -# $_[0]: The device to check (PCI or not) -# Returns: PCI class of the adapter if available, 0 if not -sub get_pci_class -{ - my ($device) = @_; - my ($subsystem, $class); - - $subsystem = sysfs_device_subsystem($device); - return 0 unless defined $subsystem && $subsystem eq "pci"; - - $class = sysfs_device_attribute($device, "class"); - return 0 unless defined $class; - $class = oct($class) if $class =~ /^0/; - return $class >> 8; -} - -# $_[0]: The number of the adapter to scan -sub scan_i2c_adapter -{ - my ($adapter_nr, $smbus_default) = @_; - my ($funcs, $chip, $addr, $class, $default, $input, @not_to_scan); - - $class = get_pci_class($i2c_adapters[$adapter_nr]->{parent}); - if (($class & 0xff00) == 0x0400) { - # Do not probe adapters on PCI multimedia cards by default - $default = 0; - } elsif ($class == 0x0c01 || $class == 0x0c05 - || find_i2c_adapter_driver($i2c_adapters[$adapter_nr]->{name})) { - $default = $smbus_default; - } else { - $default = 1; - } - - printf "Next adapter: $i2c_adapters[$adapter_nr]->{name} (i2c-$adapter_nr)\n". - "Do you want to scan it? (\%s/selectively): ", - $default ? "YES/no" : "yes/NO"; - - $input = ; - if ($input =~ /^\s*n/i - || (!$default && $input !~ /^\s*[ys]/i)) { - print "\n"; - return; - } - - if ($input =~ /^\s*s/i) { - 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 = ; - chomp($input); - @not_to_scan = parse_not_to_scan(0x03, 0x77, $input); - } - - open(local *FILE, "$dev_i2c$adapter_nr") or - (print "Can't open $dev_i2c$adapter_nr\n"), return; - binmode(FILE); - - # Can we probe this adapter? - $funcs = i2c_get_funcs(\*FILE); - if ($funcs < 0) { - print "Adapter failed to provide its functionalities, skipping.\n"; - return; - } - if (!($funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA))) { - print "Adapter cannot be probed, skipping.\n"; - return; - } - if (~$funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA)) { - print "Adapter doesn't support all probing functions.\n", - "Some addresses won't be probed.\n"; - } - - # Now scan each address in turn - foreach $addr (@{$i2c_addresses_to_scan}) { - # As the not_to_scan list is sorted, we can check it fast - shift @not_to_scan # User skipped an address which we didn't intend to probe anyway - while (@not_to_scan and $not_to_scan[0] < $addr); - if (@not_to_scan and $not_to_scan[0] == $addr) { - shift @not_to_scan; - next; - } - - if (!i2c_set_slave_addr(\*FILE, $addr)) { - add_busy_i2c_address($adapter_nr, $addr); - next; - } - - next unless i2c_probe(\*FILE, $addr, $funcs); - printf "Client found at address 0x%02x\n", $addr; - if (!i2c_safety_check(\*FILE)) { - print "Seems to be a 1-register-only device, skipping.\n"; - next; - } - - $| = 1; - foreach $chip (@chip_ids, @non_hwmon_chip_ids) { - next unless exists $chip->{i2c_addrs} - && contains($addr, @{$chip->{i2c_addrs}}); - probe_free_i2c_address($adapter_nr, $addr, $chip); - } - $| = 0; - } - print "\n"; -} - -sub scan_isa_bus -{ - my $chip_list_ref = shift; - my ($chip, $addr, $conf); - - $| = 1; - foreach $chip (@{$chip_list_ref}) { - next if not exists $chip->{isa_addrs} or not exists $chip->{isa_detect}; - foreach $addr (@{$chip->{isa_addrs}}) { - printf("\%-60s", sprintf("Probing for `\%s' at 0x\%x... ", - $chip->{name}, $addr)); - $conf = &{$chip->{isa_detect}} ($addr); - print("No\n"), next if not defined $conf; - print "Success!\n"; - printf " (confidence %d, driver `%s')\n", $conf, $chip->{driver}; - my $new_hash = { - conf => $conf, - isa_addr => $addr, - chipname => $chip->{name}, - alias_detect => $chip->{alias_detect}, - }; - add_isa_to_chips_detected($chip->{driver}, $new_hash); - } - } - $| = 0; -} - -use vars qw(%superio); - -# The following are taken from the PNP ISA spec (so it's supposed -# to be common to all Super I/O chips): -# devidreg: The device ID register(s) -# logdevreg: The logical device register -# actreg: The activation register within the logical device -# actmask: The activation bit in the activation register -# basereg: The I/O base register within the logical device -%superio = ( - devidreg => 0x20, - logdevreg => 0x07, - actreg => 0x30, - actmask => 0x01, - basereg => 0x60, -); - -sub exit_superio -{ - my ($addrreg, $datareg) = @_; - - # Some chips (SMSC, Winbond) want this - outb($addrreg, 0xaa); - - # Return to "Wait For Key" state (PNP-ISA spec) - outb($addrreg, 0x02); - outb($datareg, 0x02); -} - -# Guess if an unknown Super-I/O chip has sensors -sub guess_superio_ld -{ - my ($addrreg, $datareg, $typical_addr) = @_; - my ($oldldn, $ldn, $addr); - - # Save logical device number - outb($addrreg, $superio{logdevreg}); - $oldldn = inb($datareg); - - for ($ldn = 0; $ldn < 16; $ldn++) { - # Select logical device - outb($addrreg, $superio{logdevreg}); - outb($datareg, $ldn); - - # Read base I/O address - outb($addrreg, $superio{basereg}); - $addr = inb($datareg) << 8; - outb($addrreg, $superio{basereg} + 1); - $addr |= inb($datareg); - next unless ($addr & 0xfff8) == $typical_addr; - - printf " (logical device \%X has address 0x\%x, could be sensors)\n", - $ldn, $addr; - last; - } - - # Be nice, restore original logical device - outb($addrreg, $superio{logdevreg}); - outb($datareg, $oldldn); -} - -# Returns: features bitmask if device added to chips_detected, 0 if not -sub probe_superio -{ - my ($addrreg, $datareg, $chip) = @_; - my ($val, $addr); - - if (exists $chip->{check}) { - return 0 unless $chip->{check}($addrreg, $datareg); - } - - printf "\%-60s", "Found `$chip->{name}'"; - - # Does it have hardware monitoring capabilities? - if (!exists $chip->{driver}) { - print "\n (no information available)\n"; - return 0; - } - if ($chip->{driver} eq "not-a-sensor") { - print "\n (no hardware monitoring capabilities)\n"; - return 0; - } - if ($chip->{driver} eq "via-smbus-only") { - print "\n (hardware monitoring capabilities accessible via SMBus only)\n"; - return FEAT_SMBUS; - } - - # Switch to the sensor logical device - outb($addrreg, $superio{logdevreg}); - outb($datareg, $chip->{logdev}); - - # Get the IO base address - outb($addrreg, $superio{basereg}); - $addr = inb($datareg); - outb($addrreg, $superio{basereg} + 1); - $addr = ($addr << 8) | inb($datareg); - - # Check the activation register and base address - outb($addrreg, $superio{actreg}); - $val = inb($datareg); - if (!($val & $superio{actmask})) { - if ($addr) { - printf "\n (address 0x\%x, but not activated)\n", $addr; - } else { - print "\n (but not activated)\n"; - } - return 0; - } - if ($addr == 0) { - print "\n (but no address specified)\n"; - return 0; - } - - print "Success!\n"; - printf " (address 0x\%x, driver `%s')\n", $addr, $chip->{driver}; - my $new_hash = { - conf => 9, - isa_addr => $addr, - chipname => $chip->{name} - }; - add_isa_to_chips_detected($chip->{driver}, $new_hash); - return $chip->{features}; -} - -# Detection routine for non-standard SMSC Super I/O chips -# $_[0]: Super I/O LPC config/index port -# $_[1]: Super I/O LPC data port -# $_[2]: Reference to array of non-standard chips -# Return values: 1 if non-standard chip found, 0 otherwise -sub smsc_ns_detect_superio -{ - my ($addrreg, $datareg, $ns_chips) = @_; - my ($val, $chip); - - # read alternate device ID register - outb($addrreg, 0x0d); - $val = inb($datareg); - return 0 if $val == 0x00 || $val == 0xff; - - print "Yes\n"; - - foreach $chip (@{$ns_chips}) { - if ($chip->{devid} == $val) { - probe_superio($addrreg, $datareg, $chip); - return 1; - } - } - - printf("Found unknown non-standard chip with ID 0x%02x\n", $val); - return 1; -} - -# Returns: features supported by the device added, if any -sub scan_superio -{ - my ($addrreg, $datareg) = @_; - my ($val, $found); - my $features = 0; - - printf("Probing for Super-I/O at 0x\%x/0x\%x\n", $addrreg, $datareg); - - $| = 1; - # reset state to avoid false positives - exit_superio($addrreg, $datareg); - foreach my $family (@superio_ids) { - printf("\%-60s", "Trying family `$family->{family}'... "); - # write the password - foreach $val (@{$family->{enter}->{$addrreg}}) { - outb($addrreg, $val); - } - # call the non-standard detection routine first if it exists - if (defined($family->{ns_detect}) && - &{$family->{ns_detect}}($addrreg, $datareg, $family->{ns_chips})) { - last; - } - - # did it work? - outb($addrreg, $superio{devidreg}); - $val = inb($datareg); - outb($addrreg, $superio{devidreg} + 1); - $val = ($val << 8) | inb($datareg); - if ($val == 0x0000 || $val == 0xffff) { - print "No\n"; - next; - } - print "Yes\n"; - - $found = 0; - foreach my $chip (@{$family->{chips}}) { - if (($chip->{devid} > 0xff && - ($val & ($chip->{devid_mask} || 0xffff)) == $chip->{devid}) - || ($chip->{devid} <= 0xff && - ($val >> 8) == $chip->{devid})) { - $features |= probe_superio($addrreg, $datareg, $chip); - $found++; - } - } - - if (!$found) { - printf("Found unknown chip with ID 0x%04x\n", $val); - # Guess if a logical device could correspond to sensors - guess_superio_ld($addrreg, $datareg, $family->{guess}) - if defined $family->{guess}; - } - last; - } - exit_superio($addrreg, $datareg); - $| = 0; - return $features; -} - -sub scan_cpu -{ - my $entry = shift; - my $confidence; - - printf("\%-60s", "$entry->{name}... "); - if (defined ($confidence = $entry->{detect}())) { - print "Success!\n"; - printf " (driver `%s')\n", $entry->{driver}; - my $new_hash = { - conf => $confidence, - chipname => $entry->{name}, - }; - add_isa_to_chips_detected($entry->{driver}, $new_hash); - } else { - print "No\n"; - } -} - -################## -# CHIP DETECTION # -################## - -# This routine allows you to dynamically update the chip detection list. -# The most common use is to allow for different chip to driver mappings -# based on different linux kernels -sub chip_special_cases -{ - # Some chip to driver mappings depend on the environment - foreach my $chip (@chip_ids) { - if (ref($chip->{driver}) eq 'CODE') { - $chip->{driver} = $chip->{driver}->(); - } - } - - # Also fill the fake driver name of non-hwmon chips - foreach my $chip (@non_hwmon_chip_ids) { - $chip->{driver} = "not-a-sensor"; - } -} - -# Each function returns a confidence value. The higher this value, the more -# sure we are about this chip. This may help overrule false positives, -# although we also attempt to prevent false positives in the first place. - -# Each function returns a list. The first element is the confidence value; -# Each element after it is an SMBus address. In this way, we can detect -# chips with several SMBus addresses. The SMBus address for which the -# function was called is never returned. - -# All I2C detection functions below take at least 2 parameters: -# $_[0]: Reference to the file descriptor to access the chip -# $_[1]: Address -# Some of these functions which can detect more than one type of device, -# take a third parameter: -# $_[2]: Chip to detect - -# Registers used: 0x58 -sub mtp008_detect -{ - my ($file, $addr) = @_; - return if i2c_smbus_read_byte_data($file, 0x58) != 0xac; - return 3; -} - -# Chip to detect: 0 = LM78, 2 = LM79 -# Registers used: -# 0x40: Configuration -# 0x48: Full I2C Address -# 0x49: Device ID -sub lm78_detect -{ - my ($file, $addr, $chip) = @_; - my $reg; - - return unless i2c_smbus_read_byte_data($file, 0x48) == $addr; - return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00; - - $reg = i2c_smbus_read_byte_data($file, 0x49); - return if $chip == 0 && ($reg != 0x00 && $reg != 0x20 && $reg != 0x40); - return if $chip == 2 && ($reg & 0xfe) != 0xc0; - - # Explicitly prevent misdetection of Winbond chips - $reg = i2c_smbus_read_byte_data($file, 0x4f); - return if $reg == 0xa3 || $reg == 0x5c; - - return 6; -} - -# Chip to detect: 0 = LM75, 1 = DS75 -# Registers used: -# 0x00: Temperature -# 0x01: Configuration -# 0x02: Hysteresis -# 0x03: Overtemperature Shutdown -# 0x04-0x07: No registers -# The first detection step is based on the fact that the LM75 has only -# four registers, and cycles addresses over 8-byte boundaries. We use the -# 0x04-0x07 addresses (unused) to improve the reliability. These are not -# real registers and will always return the last returned value. This isn't -# documented. -# Note that register 0x00 may change, so we can't use the modulo trick on it. -# The DS75 is a bit different, it doesn't cycle over 8-byte boundaries, and -# all register addresses from 0x04 to 0x0f behave like 0x04-0x07 do for -# the LM75. -# Not all devices enjoy SMBus read word transactions, so we use read byte -# transactions even for the 16-bit registers. The low bits aren't very -# useful for detection anyway. -sub lm75_detect -{ - my ($file, $addr, $chip) = @_; - my $i; - my $cur = i2c_smbus_read_byte_data($file, 0x00); - my $conf = i2c_smbus_read_byte_data($file, 0x01); - - my $hyst = i2c_smbus_read_byte_data($file, 0x02, NO_CACHE); - my $maxreg = $chip == 1 ? 0x0f : 0x07; - for $i (0x04 .. $maxreg) { - return if i2c_smbus_read_byte_data($file, $i, NO_CACHE) != $hyst; - } - - my $os = i2c_smbus_read_byte_data($file, 0x03, NO_CACHE); - for $i (0x04 .. $maxreg) { - return if i2c_smbus_read_byte_data($file, $i, NO_CACHE) != $os; - } - - if ($chip == 0) { - for ($i = 8; $i <= 248; $i += 40) { - return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf - or i2c_smbus_read_byte_data($file, $i + 0x02) != $hyst - or i2c_smbus_read_byte_data($file, $i + 0x03) != $os; - } - } - - # All registers hold the same value, obviously a misdetection - return if $conf == $cur and $cur == $hyst and $cur == $os; - - # Unused bits - return if $chip == 0 and ($conf & 0xe0); - return if $chip == 1 and ($conf & 0x80); - - # Most probable value ranges - return 6 if $cur <= 100 and ($hyst >= 10 && $hyst <= 125) - and ($os >= 20 && $os <= 127) and $hyst < $os; - return 3; -} - -# Registers used: -# 0x00: Temperature -# 0x01: Configuration -# 0x02: High Limit -# 0x03: Low Limit -# 0x04: Status -# 0x07: Manufacturer ID and Product ID -sub lm73_detect -{ - my ($file, $addr) = @_; - - my $conf = i2c_smbus_read_byte_data($file, 0x01); - my $status = i2c_smbus_read_byte_data($file, 0x04); - - # Bits that always return 0 - return if ($conf & 0x0c) or ($status & 0x10); - - return if i2c_smbus_read_word_data($file, 0x07) != 0x9001; - - # Make sure the chip supports SMBus read word transactions - my $cur = i2c_smbus_read_word_data($file, 0x00); - return if $cur < 0; - my $high = i2c_smbus_read_word_data($file, 0x02); - return if $high < 0; - my $low = i2c_smbus_read_word_data($file, 0x03); - return if $low < 0; - return if ($cur & 0x0300) or (($high | $low) & 0x1f00); - - return 3; -} - -# Registers used: -# 0x00: Temperature -# 0x01: Configuration -# 0x02: Hysteresis -# 0x03: Overtemperature Shutdown -# 0x04: Low limit -# 0x05: High limit -# 0x06-0x07: No registers -# The first detection step is based on the fact that the LM77 has only -# six registers, and cycles addresses over 8-byte boundaries. We use the -# 0x06-0x07 addresses (unused) to improve the reliability. These are not -# real registers and will always return the last returned value. This isn't -# documented. -# Note that register 0x00 may change, so we can't use the modulo trick on it. -# Not all devices enjoy SMBus read word transactions, so we use read byte -# transactions even for the 16-bit registers at first. We only use read word -# transactions in the end when we are already almost certain that we have an -# LM77 chip. -sub lm77_detect -{ - my ($file, $addr) = @_; - my $i; - my $cur = i2c_smbus_read_byte_data($file, 0x00); - my $conf = i2c_smbus_read_byte_data($file, 0x01); - my $hyst = i2c_smbus_read_byte_data($file, 0x02); - my $os = i2c_smbus_read_byte_data($file, 0x03); - - my $low = i2c_smbus_read_byte_data($file, 0x04, NO_CACHE); - return if i2c_smbus_read_byte_data($file, 0x06, NO_CACHE) != $low; - return if i2c_smbus_read_byte_data($file, 0x07, NO_CACHE) != $low; - - my $high = i2c_smbus_read_byte_data($file, 0x05, NO_CACHE); - return if i2c_smbus_read_byte_data($file, 0x06, NO_CACHE) != $high; - return if i2c_smbus_read_byte_data($file, 0x07, NO_CACHE) != $high; - - for ($i = 8; $i <= 248; $i += 40) { - return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf; - return if i2c_smbus_read_byte_data($file, $i + 0x02) != $hyst; - return if i2c_smbus_read_byte_data($file, $i + 0x03) != $os; - return if i2c_smbus_read_byte_data($file, $i + 0x04) != $low; - return if i2c_smbus_read_byte_data($file, $i + 0x05) != $high; - } - - # All registers hold the same value, obviously a misdetection - return if $conf == $cur and $cur == $hyst - and $cur == $os and $cur == $low and $cur == $high; - - # Unused bits - return if ($conf & 0xe0) - or (($cur >> 4) != 0 && ($cur >> 4) != 0xf) - or (($hyst >> 4) != 0 && ($hyst >> 4) != 0xf) - or (($os >> 4) != 0 && ($os >> 4) != 0xf) - or (($low >> 4) != 0 && ($low >> 4) != 0xf) - or (($high >> 4) != 0 && ($high >> 4) != 0xf); - - # Make sure the chip supports SMBus read word transactions - foreach $i (0x00, 0x02, 0x03, 0x04, 0x05) { - return if i2c_smbus_read_word_data($file, $i) < 0; - } - - return 3; -} - -# Chip to detect: 0 = LM92, 1 = LM76, 2 = MAX6633/MAX6634/MAX6635 -# Registers used: -# 0x01: Configuration (National Semiconductor only) -# 0x02: Hysteresis -# 0x03: Critical Temp -# 0x04: Low Limit -# 0x05: High Limit -# 0x07: Manufacturer ID (LM92 only) -# One detection step is based on the fact that the LM92 and clones have a -# limited number of registers, which cycle modulo 16 address values. -# Note that register 0x00 may change, so we can't use the modulo trick on it. -# Not all devices enjoy SMBus read word transactions, so we use read byte -# transactions even for the 16-bit registers at first. We only use read -# word transactions in the end when we are already almost certain that we -# have an LM92 chip or compatible. -sub lm92_detect -{ - my ($file, $addr, $chip) = @_; - - my $conf = i2c_smbus_read_byte_data($file, 0x01); - my $hyst = i2c_smbus_read_byte_data($file, 0x02); - my $crit = i2c_smbus_read_byte_data($file, 0x03); - my $low = i2c_smbus_read_byte_data($file, 0x04); - my $high = i2c_smbus_read_byte_data($file, 0x05); - - return if $conf == 0 and $hyst == 0 and $crit == 0 - and $low == 0 and $high == 0; - - # Unused bits - return if ($chip == 0 || $chip == 1) - and ($conf & 0xE0); - - for (my $i = 0; $i <= 240; $i += 16) { - return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf; - return if i2c_smbus_read_byte_data($file, $i + 0x02) != $hyst; - return if i2c_smbus_read_byte_data($file, $i + 0x03) != $crit; - return if i2c_smbus_read_byte_data($file, $i + 0x04) != $low; - return if i2c_smbus_read_byte_data($file, $i + 0x05) != $high; - } - - return if $chip == 0 - and i2c_smbus_read_word_data($file, 0x07) != 0x0180; - - # Make sure the chip supports SMBus read word transactions - $hyst = i2c_smbus_read_word_data($file, 0x02); - return if $hyst < 0; - $crit = i2c_smbus_read_word_data($file, 0x03); - return if $crit < 0; - $low = i2c_smbus_read_word_data($file, 0x04); - return if $low < 0; - $high = i2c_smbus_read_word_data($file, 0x05); - return if $high < 0; - - foreach my $temp ($hyst, $crit, $low, $high) { - return if $chip == 2 and ($temp & 0x7F00); - return if $chip != 2 and ($temp & 0x0700); - } - - return ($chip == 0) ? 4 : 2; -} - -# Registers used: -# 0xAA: Temperature -# 0xA1: High limit -# 0xA2: Low limit -# 0xA8: Counter -# 0xA9: Slope -# 0xAC: Configuration -# Detection is weak. We check if bit 4 (NVB) is clear, because it is -# unlikely to be set (would mean that EEPROM is currently being accessed). -# We also check the value of the counter and slope registers, the datasheet -# doesn't mention the possible values but the conversion formula together -# with experimental evidence suggest possible sanity checks. -# Not all devices enjoy SMBus read word transactions, so we do as much as -# possible with read byte transactions first, and only use read word -# transactions second. -sub ds1621_detect -{ - my ($file, $addr) = @_; - - my $conf = i2c_smbus_read_byte_data($file, 0xAC); - return if ($conf & 0x10); - - my $temp = i2c_smbus_read_word_data($file, 0xAA); - return if $temp < 0 || ($temp & 0x0f00); - # On the DS1631, the following two checks are too strict in theory, - # but in practice I very much doubt that anyone will set temperature - # limits not a multiple of 0.5 degrees C. - my $high = i2c_smbus_read_word_data($file, 0xA1); - return if $high < 0 || ($high & 0x7f00); - my $low = i2c_smbus_read_word_data($file, 0xA2); - return if $low < 0 || ($low & 0x7f00); - - return if ($temp == 0 && $high == 0 && $low == 0 && $conf == 0); - - # Old versions of the DS1621 apparently don't have the counter and - # slope registers (or they return crap) - my $counter = i2c_smbus_read_byte_data($file, 0xA8); - my $slope = i2c_smbus_read_byte_data($file, 0xA9); - return ($slope == 0x10 && $counter <= $slope) ? 3 : 2; -} - -# Registers used: -# 0x00: Configuration register -# 0x02: Interrupt state register -# 0x2a-0x3d: Limits registers -# This one is easily misdetected since it doesn't provide identification -# registers. So we have to use some tricks: -# - 6-bit addressing, so limits readings modulo 0x40 should be unchanged -# - positive temperature limits -# - limits order correctness -# Hopefully this should limit the rate of false positives, without increasing -# the rate of false negatives. -# Thanks to Lennard Klein for testing on a non-LM80 chip, which was -# previously misdetected, and isn't anymore. For reference, it scored -# a final confidence of 0, and changing from strict limit comparisons -# to loose comparisons did not change the score. -sub lm80_detect -{ - my ($file, $addr) = @_; - my ($i, $reg); - - return if (i2c_smbus_read_byte_data($file, 0x00) & 0x80) != 0; - return if (i2c_smbus_read_byte_data($file, 0x02) & 0xc0) != 0; - - for ($i = 0x2a; $i <= 0x3d; $i++) { - $reg = i2c_smbus_read_byte_data($file, $i); - return if i2c_smbus_read_byte_data($file, $i+0x40) != $reg; - return if i2c_smbus_read_byte_data($file, $i+0x80) != $reg; - return if i2c_smbus_read_byte_data($file, $i+0xc0) != $reg; - } - - # Refine a bit by checking whether limits are in the correct order - # (min> 1) - 4; - # $confidence is now between -4 and 3 - - return unless $confidence > 0; - - return $confidence; -} - -# Registers used: -# 0x02: Status 1 -# 0x03: Configuration -# 0x04: Company ID of LM84 -# 0x35: Status 2 -# 0xfe: Manufacturer ID -# 0xff: Chip ID / die revision -# We can use the LM84 Company ID register because the LM83 and the LM82 are -# compatible with the LM84. -# The LM83 chip ID is missing from the datasheet and was contributed by -# Magnus Forsstrom: 0x03. -# At least some revisions of the LM82 seem to be repackaged LM83, so they -# have the same chip ID, and temp2/temp4 will be stuck in "OPEN" state. -# For this reason, we don't even try to distinguish between both chips. -# Thanks to Ben Gardner for reporting. -sub lm83_detect -{ - my ($file, $addr) = @_; - return if i2c_smbus_read_byte_data($file, 0xfe) != 0x01; - my $chipid = i2c_smbus_read_byte_data($file, 0xff); - return if $chipid != 0x01 && $chipid != 0x03; - - my $confidence = 4; - $confidence++ - if (i2c_smbus_read_byte_data($file, 0x02) & 0xa8) == 0x00; - $confidence++ - if (i2c_smbus_read_byte_data($file, 0x03) & 0x41) == 0x00; - $confidence++ - if i2c_smbus_read_byte_data($file, 0x04) == 0x00; - $confidence++ - if (i2c_smbus_read_byte_data($file, 0x35) & 0x48) == 0x00; - - return $confidence; -} - -# Chip to detect: 0 = LM90, 1 = LM89/LM99, 2 = LM86, 3 = ADM1032, -# 4 = MAX6654/MAX6690, 5 = ADT7461, -# 6 = MAX6646/MAX6647/MAX6648/MAX6649/MAX6692, -# 7 = MAX6680/MAX6681, 8 = W83L771W/G, 9 = TMP401, 10 = TMP411 -# Registers used: -# 0x03: Configuration -# 0x04: Conversion rate -# 0xfe: Manufacturer ID -# 0xff: Chip ID / die revision -sub lm90_detect -{ - my ($file, $addr, $chip) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0xfe); - my $cid = i2c_smbus_read_byte_data($file, 0xff); - my $conf = i2c_smbus_read_byte_data($file, 0x03); - my $rate = i2c_smbus_read_byte_data($file, 0x04); - - if ($chip == 0) { - return if ($conf & 0x2a) != 0; - return if $rate > 0x09; - return if $mid != 0x01; # National Semiconductor - return 8 if $cid == 0x21; # LM90 - return 6 if ($cid & 0x0f) == 0x20; - } - if ($chip == 1) { - return if ($conf & 0x2a) != 0; - return if $rate > 0x09; - return if $mid != 0x01; # National Semiconductor - return 8 if $addr == 0x4c and $cid == 0x31; # LM89/LM99 - return 8 if $addr == 0x4d and $cid == 0x34; # LM89-1/LM99-1 - return 6 if ($cid & 0x0f) == 0x30; - } - if ($chip == 2) { - return if ($conf & 0x2a) != 0; - return if $rate > 0x09; - return if $mid != 0x01; # National Semiconductor - return 8 if $cid == 0x11; # LM86 - return 6 if ($cid & 0xf0) == 0x10; - } - if ($chip == 3) { - return if ($conf & 0x3f) != 0; - return if $rate > 0x0a; - return if $mid != 0x41; # Analog Devices - return 6 if ($cid & 0xf0) == 0x40; # ADM1032 - } - if ($chip == 4) { - return if ($conf & 0x07) != 0; - return if $rate > 0x07; - return if $mid != 0x4d; # Maxim - return 8 if $cid == 0x08; # MAX6654/MAX6690 - } - if ($chip == 5) { - return if ($conf & 0x1b) != 0; - return if $rate > 0x0a; - return if $mid != 0x41; # Analog Devices - return 8 if $cid == 0x51; # ADT7461 - } - if ($chip == 6) { - return if ($conf & 0x3f) != 0; - return if $rate > 0x07; - return if $mid != 0x4d; # Maxim - return 8 if $cid == 0x59; # MAX6648/MAX6692 - } - if ($chip == 7) { - return if ($conf & 0x03) != 0; - return if $rate > 0x07; - return if $mid != 0x4d; # Maxim - return 8 if $cid == 0x01; # MAX6680/MAX6681 - } - if ($chip == 8) { - return if ($conf & 0x2a) != 0; - return if $rate > 0x09; - return if $mid != 0x5c; # Winbond - return 6 if $cid == 0x00; # W83L771W/G - } - if ($chip == 9) { - return if ($conf & 0x1B) != 0; - return if $rate > 0x0F; - return if $mid != 0x55; # Texas Instruments - return 8 if $cid == 0x11; # TMP401 - } - if ($chip == 10) { - return if ($conf & 0x1B) != 0; - return if $rate > 0x0F; - return if $mid != 0x55; # Texas Instruments - return 6 if ($addr == 0x4c && $cid == 0x12); # TMP411A - return 6 if ($addr == 0x4d && $cid == 0x13); # TMP411B - return 6 if ($addr == 0x4e && $cid == 0x10); # TMP411C - } - return; -} - -# Chip to detect: 0 = TMP421, 1 = TMP422, 2 = TMP423 -# Registers used: -# 0xfe: Manufactorer ID -# 0xff: Device ID -sub tmp42x_detect() -{ - my ($file, $addr, $chip) = @_; - - my $mid = i2c_smbus_read_byte_data($file, 0xfe); - my $cid = i2c_smbus_read_byte_data($file, 0xff); - - return if ($mid != 0x55); - - return 6 if ($chip == 0 && $cid == 0x21); # TMP421 - return 6 if ($chip == 1 && $cid == 0x22); # TMP422 - return 6 if ($chip == 2 && $cid == 0x23); # TMP423 - - return; -} - -# Registers used: -# 0x03: Configuration (no low nibble, returns the previous low nibble) -# 0x04: Conversion rate -# 0xfe: Manufacturer ID -# 0xff: no register -sub max6657_detect -{ - my ($file, $addr) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0xfe, NO_CACHE); - my $cid = i2c_smbus_read_byte_data($file, 0xff, NO_CACHE); - my $conf = i2c_smbus_read_byte_data($file, 0x03, NO_CACHE); - - return if $mid != 0x4d; # Maxim - return if ($conf & 0x1f) != 0x0d; - return if $cid != 0x4d; # No register, returns previous value - - my $rate = i2c_smbus_read_byte_data($file, 0x04, NO_CACHE); - return if $rate > 0x09; - - $cid = i2c_smbus_read_byte_data($file, 0xff, NO_CACHE); - $conf = i2c_smbus_read_byte_data($file, 0x03, NO_CACHE); - return if ($conf & 0x0f) != $rate; - return if $cid != $rate; # No register, returns previous value - - return 5; -} - -# Chip to detect: 0 = LM95231, 1 = LM95241 -# Registers used: -# 0x02: Status (3 unused bits) -# 0x03: Configuration (3 unused bits) -# 0x06: Remote diode filter control (6 unused bits) -# 0x30: Remote diode model type select (6 unused bits) -# 0xfe: Manufacturer ID -# 0xff: Revision ID -sub lm95231_detect -{ - my ($file, $addr, $chip) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0xfe); - my $cid = i2c_smbus_read_byte_data($file, 0xff); - - return if $mid != 0x01; # National Semiconductor - return if $chip == 0 && $cid != 0xa1; # LM95231 - return if $chip == 1 && $cid != 0xa4; # LM95231 - - return if i2c_smbus_read_byte_data($file, 0x02) & 0x70; - return if i2c_smbus_read_byte_data($file, 0x03) & 0x89; - return if i2c_smbus_read_byte_data($file, 0x06) & 0xfa; - return if i2c_smbus_read_byte_data($file, 0x30) & 0xfa; - - return 6; -} - -# Registers used: -# 0x03: Configuration 1 -# 0x24: Configuration 2 -# 0x3d: Manufacturer ID -# 0x3e: Device ID -sub adt7481_detect -{ - my ($file, $addr) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x3d); - my $cid = i2c_smbus_read_byte_data($file, 0x3e); - my $conf1 = i2c_smbus_read_byte_data($file, 0x03); - my $conf2 = i2c_smbus_read_byte_data($file, 0x24); - - return if ($conf1 & 0x10) != 0; - return if ($conf2 & 0x7f) != 0; - return if $mid != 0x41; # Analog Devices - return if $cid != 0x81; # ADT7481 - - return 6; -} - -# Chip to detect: 1 = LM63, 2 = F75363SG, 3 = LM64 -# Registers used: -# 0xfe: Manufacturer ID -# 0xff: Chip ID / die revision -# 0x03: Configuration (two or three unused bits) -# 0x16: Alert mask (two or three unused bits) -sub lm63_detect -{ - my ($file, $addr, $chip) = @_; - - my $mid = i2c_smbus_read_byte_data($file, 0xfe); - my $cid = i2c_smbus_read_byte_data($file, 0xff); - my $conf = i2c_smbus_read_byte_data($file, 0x03); - my $mask = i2c_smbus_read_byte_data($file, 0x16); - - if ($chip == 1) { - return if $mid != 0x01 # National Semiconductor - || $cid != 0x41; # LM63 - return if ($conf & 0x18) != 0x00 - || ($mask & 0xa4) != 0xa4; - } elsif ($chip == 2) { - return if $mid != 0x23 # Fintek - || $cid != 0x20; # F75363SG - return if ($conf & 0x1a) != 0x00 - || ($mask & 0x84) != 0x00; - } elsif ($chip == 3) { - return if $mid != 0x01 # National Semiconductor - || $cid != 0x51; # LM64 - return if ($conf & 0x18) != 0x00 - || ($mask & 0xa4) != 0xa4; - } - - return 6; -} - -# Registers used: -# 0x02, 0x03: Fan support -# 0x06: Temperature support -# 0x07, 0x08, 0x09: Fan config -# 0x0d: Manufacturer ID -# 0x0e: Chip ID / die revision -sub adm1029_detect -{ - my ($file, $addr) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x0d); - my $cid = i2c_smbus_read_byte_data($file, 0x0e); - my $cfg; - - return unless $mid == 0x41; # Analog Devices - return unless ($cid & 0xF0) == 0x00; # ADM1029 - - # Extra check on unused bits - $cfg = i2c_smbus_read_byte_data($file, 0x02); - return unless $cfg == 0x03; - $cfg = i2c_smbus_read_byte_data($file, 0x06); - return unless ($cfg & 0xF9) == 0x01; - foreach my $reg (0x03, 0x07, 0x08, 0x09) { - $cfg = i2c_smbus_read_byte_data($file, $reg); - return unless ($cfg & 0xFC) == 0x00; - } - - return 7; -} - -# Chip to detect: 0 = ADM1030, 1 = ADM1031 -# Registers used: -# 0x01: Config 2 -# 0x03: Status 2 -# 0x0d, 0x0e, 0x0f: Temperature offsets -# 0x22: Fan speed config -# 0x3d: Chip ID -# 0x3e: Manufacturer ID -# 0x3f: Die revision -sub adm1031_detect -{ - my ($file, $addr, $chip) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x3e); - my $cid = i2c_smbus_read_byte_data($file, 0x3d); - my $drev = i2c_smbus_read_byte_data($file, 0x3f); - my $conf2 = i2c_smbus_read_byte_data($file, 0x01); - my $stat2 = i2c_smbus_read_byte_data($file, 0x03); - my $fsc = i2c_smbus_read_byte_data($file, 0x22); - my $lto = i2c_smbus_read_byte_data($file, 0x0d); - my $r1to = i2c_smbus_read_byte_data($file, 0x0e); - my $r2to = i2c_smbus_read_byte_data($file, 0x0f); - my $confidence = 3; - - if ($chip == 0) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x30; # ADM1030 - $confidence++ if ($drev & 0x70) == 0x00; - $confidence++ if ($conf2 & 0x4A) == 0x00; - $confidence++ if ($stat2 & 0x3F) == 0x00; - $confidence++ if ($fsc & 0xF0) == 0x00; - $confidence++ if ($lto & 0x70) == 0x00; - $confidence++ if ($r1to & 0x70) == 0x00; - return $confidence; - } - if ($chip == 1) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x31; # ADM1031 - $confidence++ if ($drev & 0x70) == 0x00; - $confidence++ if ($lto & 0x70) == 0x00; - $confidence++ if ($r1to & 0x70) == 0x00; - $confidence++ if ($r2to & 0x70) == 0x00; - return $confidence; - } -} - -# Chip to detect: 0 = ADM1033, 1 = ADM1034 -# Registers used: -# 0x3d: Chip ID -# 0x3e: Manufacturer ID -# 0x3f: Die revision -sub adm1034_detect -{ - my ($file, $addr, $chip) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x3e); - my $cid = i2c_smbus_read_byte_data($file, 0x3d); - my $drev = i2c_smbus_read_byte_data($file, 0x3f); - - if ($chip == 0) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x33; # ADM1033 - return if ($drev & 0xf8) != 0x00; - return 6 if $drev == 0x02; - return 4; - } - if ($chip == 1) { - return if $mid != 0x41; # Analog Devices - return if $cid != 0x34; # ADM1034 - return if ($drev & 0xf8) != 0x00; - return 6 if $drev == 0x02; - return 4; - } -} - -# Chip to detect: 0 = ADT7467/ADT7468, 1 = ADT7476, 2 = ADT7462, 3 = ADT7466, -# 4 = ADT7470 -# Registers used: -# 0x3d: Chip ID -# 0x3e: Manufacturer ID -# 0x3f: Die revision -sub adt7467_detect -{ - my ($file, $addr, $chip) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x3e); - my $cid = i2c_smbus_read_byte_data($file, 0x3d); - my $drev = i2c_smbus_read_byte_data($file, 0x3f); - - return if $mid != 0x41; # Analog Devices - - if ($chip == 0) { - return if $cid != 0x68; # ADT7467 - return if ($drev & 0xf0) != 0x70; - return 7 if $drev == 0x71 || $drev == 0x72; - return 5; - } - if ($chip == 1) { - return if $cid != 0x76; # ADT7476 - return if ($drev & 0xf0) != 0x60; - return 7 if $drev == 0x69; - return 5; - } - if ($chip == 2) { - return if $cid != 0x62; # ADT7462 - return if ($drev & 0xf0) != 0x00; - return 7 if $drev == 0x04; - return 5; - } - if ($chip == 3) { - return if $cid != 0x66; # ADT7466 - return if ($drev & 0xf0) != 0x00; - return 7 if $drev == 0x02; - return 5; - } - if ($chip == 4) { - return if $cid != 0x70; # ADT7470 - return if ($drev & 0xf0) != 0x00; - return 7 if $drev == 0x00; - return 5; - } -} - -# Chip to detect: 0 = ADT7473, 1 = ADT7475 -# Registers used: -# 0x3d: Chip ID -# 0x3e: Manufacturer ID -sub adt7473_detect -{ - my ($file, $addr, $chip) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x3e); - my $cid = i2c_smbus_read_byte_data($file, 0x3d); - - return if $mid != 0x41; # Analog Devices - - return if $chip == 0 && $cid != 0x73; # ADT7473 - return if $chip == 1 && $cid != 0x75; # ADT7475 - return 5; -} - -# Registers used: -# 0x3e: Manufacturer ID -# 0x3f: Chip ID -sub adt7490_detect -{ - my ($file, $addr, $chip) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x3e); - my $cid = i2c_smbus_read_byte_data($file, 0x3f); - - return if $mid != 0x41; # Analog Devices - return if ($cid & 0xfc) != 0x6c; # ADT7490 - return 5; -} - -# Chip to detect: 0 = aSC7512, 1 = aSC7611, 2 = aSC7621 -# Registers used: -# 0x3e: Manufacturer ID -# 0x3f: Version -sub andigilog_detect -{ - my ($file, $addr, $chip) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0x3e); - my $cid = i2c_smbus_read_byte_data($file, 0x3f); - - return if $mid != 0x61; # Andigilog - - return if $chip == 0 && $cid != 0x62; - return if $chip == 1 && $cid != 0x69; - return if $chip == 2 && ($cid != 0x6C && $cid != 0x6D); - return 5; -} - -# Registers used: -# 0xfe: Manufacturer ID -# 0xff: Die Code -sub andigilog_aSC7511_detect -{ - my ($file, $addr) = @_; - my $mid = i2c_smbus_read_byte_data($file, 0xfe); - my $die = i2c_smbus_read_byte_data($file, 0xff); - - return if $mid != 0x61; # Andigilog - return if $die != 0x00; - return 3; -} - -# Chip to detect: 0 = LM85, 1 = LM96000, 2 = ADM1027, 3 = ADT7463, -# 4 = EMC6D100/101, 5 = EMC6D102, 6 = EMC6D103, -# 7 = WPCD377I (no sensors) -# Registers used: -# 0x3e: Vendor register -# 0x3d: Device ID register (Analog Devices only) -# 0x3f: Version/Stepping register -sub lm85_detect -{ - my ($file, $addr, $chip) = @_; - my $vendor = i2c_smbus_read_byte_data($file, 0x3e); - my $verstep = i2c_smbus_read_byte_data($file, 0x3f); - - if ($chip == 0) { - return if $vendor != 0x01; # National Semiconductor - return if $verstep != 0x60 # LM85 C - && $verstep != 0x62; # LM85 B - } elsif ($chip == 1 || $chip == 7) { - return if $vendor != 0x01; # National Semiconductor - return if $verstep != 0x68 # LM96000 - && $verstep != 0x69; # LM96000 - } elsif ($chip == 2) { - return if $vendor != 0x41; # Analog Devices - return if $verstep != 0x60; # ADM1027 - } elsif ($chip == 3) { - return if $vendor != 0x41; # Analog Devices - return if $verstep != 0x62 # ADT7463 - && $verstep != 0x6a; # ADT7463 C - } elsif ($chip == 4) { - return if $vendor != 0x5c; # SMSC - return if $verstep != 0x60 # EMC6D100/101 A0 - && $verstep != 0x61; # EMC6D100/101 A1 - } elsif ($chip == 5) { - return if $vendor != 0x5c; # SMSC - return if $verstep != 0x65; # EMC6D102 - } elsif ($chip == 6) { - return if $vendor != 0x5c; # SMSC - return if $verstep != 0x68; # EMC6D103 - } - - if ($vendor == 0x41) { # Analog Devices - return if i2c_smbus_read_byte_data($file, 0x3d) != 0x27; - return 8; - } - - if ($chip == 1 || $chip == 7) { - # Differenciate between real LM96000 and Winbond WPCD377I. - # The latter emulate the former except that it has no - # hardware monitoring function so the readings are always - # 0. - my ($in_temp, $fan, $i); - - for ($i = 0; $i < 8; $i++) { - $in_temp = i2c_smbus_read_byte_data($file, 0x20 + $i); - $fan = i2c_smbus_read_byte_data($file, 0x28 + $i); - if ($in_temp != 0x00 or $fan != 0xff) { - return 7 if $chip == 1; - return; - } - } - return 7 if $chip == 7; - return; - } - - return 7; -} - -# Chip to detect: 0 = LM87, 1 = ADM1024 -# Registers used: -# 0x3e: Company ID -# 0x3f: Revision -# 0x40: Configuration -sub lm87_detect -{ - my ($file, $addr, $chip) = @_; - my $cid = i2c_smbus_read_byte_data($file, 0x3e); - my $rev = i2c_smbus_read_byte_data($file, 0x3f); - - if ($chip == 0) { - return if $cid != 0x02; # National Semiconductor - return if ($rev & 0xfc) != 0x04; # LM87 - } - if ($chip == 1) { - return if $cid != 0x41; # Analog Devices - return if ($rev & 0xf0) != 0x10; # ADM1024 - } - - my $cfg = i2c_smbus_read_byte_data($file, 0x40); - return if ($cfg & 0x80) != 0x00; - - return 7; -} - -# Chip to detect: 0 = W83781D, 1 = W83782D, 2 = W83783S, 3 = W83627HF, -# 4 = AS99127F (rev.1), 5 = AS99127F (rev.2), 6 = ASB100, -# 7 = W83791D, 8 = W83792D, 9 = W83627EHF, -# 10 = W83627DHG/W83667HG/W83677HG -# Registers used: -# 0x48: Full I2C Address -# 0x4a: I2C addresses of emulated LM75 chips -# 0x4e: Vendor ID byte selection, and bank selection -# 0x4f: Vendor ID -# 0x58: Device ID (only when in bank 0) -# Note: Fails if the W8378xD is not in bank 0! -# Note: Asus chips do not have their I2C address at register 0x48? -# AS99127F rev.1 and ASB100 have 0x00, confirmation wanted for -# AS99127F rev.2. -sub w83781d_detect -{ - my ($file, $addr, $chip) = @_; - my ($reg1, $reg2, @res); - - return unless (i2c_smbus_read_byte_data($file, 0x48) == $addr) - or ($chip >= 4 && $chip <= 6); - - $reg1 = i2c_smbus_read_byte_data($file, 0x4e); - $reg2 = i2c_smbus_read_byte_data($file, 0x4f); - if ($chip == 4) { # Asus AS99127F (rev.1) - return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xc3) or - (($reg1 & 0x80) == 0x80 and $reg2 == 0x12); - } elsif ($chip == 6) { # Asus ASB100 - return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0x94) or - (($reg1 & 0x80) == 0x80 and $reg2 == 0x06); - } else { # Winbond and Asus AS99127F (rev.2) - return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or - (($reg1 & 0x80) == 0x80 and $reg2 == 0x5c); - } - - return unless ($reg1 & 0x07) == 0x00; - - $reg1 = i2c_smbus_read_byte_data($file, 0x58); - return if $chip == 0 and ($reg1 != 0x10 && $reg1 != 0x11); - return if $chip == 1 and $reg1 != 0x30; - return if $chip == 2 and $reg1 != 0x40; - return if $chip == 3 and $reg1 != 0x21; - return if $chip == 4 and $reg1 != 0x31; - return if $chip == 5 and $reg1 != 0x31; - return if $chip == 6 and $reg1 != 0x31; - return if $chip == 7 and $reg1 != 0x71; - return if $chip == 8 and $reg1 != 0x7a; - return if $chip == 9 and ($reg1 != 0x88 && $reg1 != 0xa1); - return if $chip == 10 and $reg1 != 0xc1; - # Default address is 0x2d - @res = ($addr != 0x2d) ? (7) : (8); - return @res if $chip >= 9; # No subclients - - $reg1 = i2c_smbus_read_byte_data($file, 0x4a); - push @res, ($reg1 & 0x07) + 0x48 unless $reg1 & 0x08; - push @res, (($reg1 & 0x70) >> 4) + 0x48 - unless ($reg1 & 0x80 or $chip == 2); - return @res; -} - -# Registers used: -# 0x0b: Full I2C Address -# 0x0c: I2C addresses of emulated LM75 chips -# 0x00: Vendor ID byte selection, and bank selection(Bank 0, 1, 2) -# 0x0d: Vendor ID(Bank 0, 1, 2) -# 0x0e: Device ID(Bank 0, 1, 2) -sub w83793_detect -{ - my ($file, $addr) = @_; - my ($bank, $reg, @res); - - $bank = i2c_smbus_read_byte_data($file, 0x00); - $reg = i2c_smbus_read_byte_data($file, 0x0d); - - return unless (($bank & 0x80) == 0x00 and $reg == 0xa3) or - (($bank & 0x80) == 0x80 and $reg == 0x5c); - - $reg = i2c_smbus_read_byte_data($file, 0x0e); - return if $reg != 0x7b; - - # If bank 0 is selected, we can do more checks - return 6 unless ($bank & 0x07) == 0; - $reg = i2c_smbus_read_byte_data($file, 0x0b); - return unless ($reg == ($addr << 1)); - - $reg = i2c_smbus_read_byte_data($file, 0x0c); - @res = (8); - push @res, ($reg & 0x07) + 0x48 unless $reg & 0x08; - push @res, (($reg & 0x70) >> 4) + 0x48 unless $reg & 0x80; - return @res; -} - -# Registers used: -# 0xfc: Full I2C Address -# 0x00: Vendor ID byte selection, and bank selection(Bank 0, 1, 2) -# 0xfd: Vendor ID(Bank 0, 1, 2) -# 0xfe: Device ID(Bank 0, 1, 2) -sub w83795_detect -{ - my ($bank, $reg); - my ($file, $addr) = @_; - - $bank = i2c_smbus_read_byte_data($file, 0x00); - $reg = i2c_smbus_read_byte_data($file, 0xfd); - - return unless (($bank & 0x80) == 0x00 and $reg == 0xa3) or - (($bank & 0x80) == 0x80 and $reg == 0x5c); - - $reg = i2c_smbus_read_byte_data($file, 0xfe); - return if $reg != 0x79; - - # If bank 0 is selected, we can do more checks - return 6 unless ($bank & 0x07) == 0; - $reg = i2c_smbus_read_byte_data($file, 0xfc) & 0x7f; - return unless ($reg == $addr); - - return 8; -} - -# Registers used: -# 0x48: Full I2C Address -# 0x4e: Vendor ID byte selection -# 0x4f: Vendor ID -# 0x58: Device ID -# Note that the datasheet was useless and this detection routine -# is based on dumps we received from users. Also, the W83781SD is *NOT* -# a hardware monitoring chip as far as we know, but we still want to -# detect it so that people won't keep reporting it as an unknown chip -# we should investigate about. -sub w83791sd_detect -{ - my ($file, $addr) = @_; - my ($reg1, $reg2); - - return unless (i2c_smbus_read_byte_data($file, 0x48) == $addr); - - $reg1 = i2c_smbus_read_byte_data($file, 0x4e); - $reg2 = i2c_smbus_read_byte_data($file, 0x4f); - return unless (!($reg1 & 0x80) && $reg2 == 0xa3) - || (($reg1 & 0x80) && $reg2 == 0x5c); - - $reg1 = i2c_smbus_read_byte_data($file, 0x58); - return unless $reg1 == 0x72; - - return 3; -} - -# Registers used: -# 0x4e: Vendor ID high byte -# 0x4f: Vendor ID low byte -# 0x58: Device ID -# Note: The values were given by Alex van Kaam, we don't have datasheets -# to confirm. -sub mozart_detect -{ - my ($file, $addr) = @_; - my ($vid, $dev); - - $vid = (i2c_smbus_read_byte_data($file, 0x4e) << 8) - + i2c_smbus_read_byte_data($file, 0x4f); - $dev = i2c_smbus_read_byte_data($file, 0x58); - - return unless ($dev == 0x56 && $vid == 0x9436) # ASM58 - || ($dev == 0x56 && $vid == 0x9406) # AS2K129R - || ($dev == 0x10 && $vid == 0x5ca3); - - return 5; -} - -# Chip to detect: 0 = GL518SM, 1 = GL520SM -# Registers used: -# 0x00: Device ID -# 0x01: Revision ID -# 0x03: Configuration -sub gl518sm_detect -{ - my ($file, $addr, $chip) = @_; - my $reg; - - $reg = i2c_smbus_read_byte_data($file, 0x00); - return if $chip == 0 && $reg != 0x80; - return if $chip == 1 && $reg != 0x20; - - return unless (i2c_smbus_read_byte_data($file, 0x03) & 0x80) == 0x00; - $reg = i2c_smbus_read_byte_data($file, 0x01); - return unless $reg == 0x00 or $reg == 0x80; - return 6; -} - -# Registers used: -# 0x00: Device ID -# 0x03: Configuration -# Mediocre detection -sub gl525sm_detect -{ - my ($file, $addr) = @_; - return unless i2c_smbus_read_byte_data($file, 0x00) == 0x25; - return unless (i2c_smbus_read_byte_data($file, 0x03) & 0x80) == 0x00; - return 5; -} - -# Chip to detect: 0 = ADM9240, 1 = DS1780, 2 = LM81 -# Registers used: -# 0x3e: Company ID -# 0x40: Configuration -# 0x48: Full I2C Address -sub adm9240_detect -{ - my ($file, $addr, $chip) = @_; - my $reg; - $reg = i2c_smbus_read_byte_data($file, 0x3e); - return unless ($chip == 0 and $reg == 0x23) or - ($chip == 1 and $reg == 0xda) or - ($chip == 2 and $reg == 0x01); - return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00; - return unless i2c_smbus_read_byte_data($file, 0x48) == $addr; - - return 7; -} - -# Chip to detect: 0 = ADM1022, 1 = THMC50, 2 = ADM1028, 3 = THMC51 -# Registers used: -# 0x3e: Company ID -# 0x3f: Revision -# 0x40: Configuration -sub adm1022_detect -{ - my ($file, $addr, $chip) = @_; - my $reg; - $reg = i2c_smbus_read_byte_data($file, 0x3e); - return unless ($chip == 0 and $reg == 0x41) or - ($chip == 1 and $reg == 0x49) or - ($chip == 2 and $reg == 0x41) or - ($chip == 3 and $reg == 0x49); - $reg = i2c_smbus_read_byte_data($file, 0x40); - return if ($reg & 0x10); # Soft Reset always reads 0 - return if ($chip != 0 and ($reg & 0x80)); # Reserved on THMC50 and ADM1028 - $reg = i2c_smbus_read_byte_data($file, 0x3f) & 0xf0; - return unless ($chip == 0 and $reg == 0xc0) or - ($chip == 1 and $reg == 0xc0) or - ($chip == 2 and $reg == 0xd0) or - ($chip == 3 and $reg == 0xd0); - return 8; -} - -# Chip to detect: 0 = ADM1025, 1 = NE1619 -# Registers used: -# 0x3e: Company ID -# 0x3f: Revision -# 0x40: Configuration -# 0x41: Status 1 -# 0x42: Status 2 -sub adm1025_detect -{ - my ($file, $addr, $chip) = @_; - my $reg; - - $reg = i2c_smbus_read_byte_data($file, 0x3e); - return if ($chip == 0) and ($reg != 0x41); - return if ($chip == 1) and ($reg != 0xA1); - - return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00; - return unless (i2c_smbus_read_byte_data($file, 0x41) & 0xC0) == 0x00; - return unless (i2c_smbus_read_byte_data($file, 0x42) & 0xBC) == 0x00; - return unless (i2c_smbus_read_byte_data($file, 0x3f) & 0xf0) == 0x20; - - return 8; -} - -# Registers used: -# 0x16: Company ID -# 0x17: Revision -sub adm1026_detect -{ - my ($file, $addr) = @_; - my $reg; - $reg = i2c_smbus_read_byte_data($file, 0x16); - return unless ($reg == 0x41); - return unless (i2c_smbus_read_byte_data($file, 0x17) & 0xf0) == 0x40; - return 8; -} - -# Chip to detect: 0 = ADM1021, 1 = ADM1021A/ADM1023, 2 = MAX1617, 3 = MAX1617A, -# 4 = THMC10, 5 = LM84, 6 = GL523, 7 = MC1066 -# Registers used: -# 0x04: Company ID (LM84 only) -# 0xfe: Company ID (all but LM84 and MAX1617) -# 0xff: Revision (ADM1021, ADM1021A/ADM1023 and MAX1617A) -# 0x02: Status -# 0x03: Configuration -# 0x04: Conversion rate -# 0x00-0x01, 0x05-0x08: Temperatures (MAX1617 and LM84) -# Note: Especially the MAX1617 has very bad detection; we give it a low -# confidence value. -sub adm1021_detect -{ - my ($file, $addr, $chip) = @_; - my $man_id = i2c_smbus_read_byte_data($file, 0xfe); - my $rev = i2c_smbus_read_byte_data($file, 0xff); - my $conf = i2c_smbus_read_byte_data($file, 0x03); - my $status = i2c_smbus_read_byte_data($file, 0x02); - my $convrate = i2c_smbus_read_byte_data($file, 0x04); - - # Check manufacturer IDs and product revisions when available - return if $chip == 0 and $man_id != 0x41 || ($rev & 0xf0) != 0x00; - return if $chip == 1 and $man_id != 0x41 || ($rev & 0xf0) != 0x30; - return if $chip == 3 and $man_id != 0x4d || $rev != 0x01; - return if $chip == 4 and $man_id != 0x49; - return if $chip == 5 and $convrate != 0x00; - return if $chip == 6 and $man_id != 0x23; - return if $chip == 7 and $man_id != 0x54; - - # Check unused bits - if ($chip == 5) { # LM84 - return if ($status & 0xab) != 0; - return if ($conf & 0x7f) != 0; - } else { - return if ($status & 0x03) != 0; - return if ($conf & 0x3f) != 0; - return if ($convrate & 0xf8) != 0; - } - - # 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. - if ($chip == 2 || $chip == 5) { - my $lte = i2c_smbus_read_byte_data($file, 0x00); - my $rte = i2c_smbus_read_byte_data($file, 0x01); - my $lhi = i2c_smbus_read_byte_data($file, 0x05); - my $rhi = i2c_smbus_read_byte_data($file, 0x07); - my $llo = i2c_smbus_read_byte_data($file, 0x06); - my $rlo = i2c_smbus_read_byte_data($file, 0x08); - - # If all registers hold the same value, it has to be a misdetection - return if $lte == $rte and $lte == $lhi and $lte == $rhi - and $lte == $llo and $lte == $rlo; - - # Negative temperatures - return if ($lte & 0x80) or ($rte & 0x80); - # Negative high limits - return if ($lhi & 0x80) or ($rhi & 0x80); - # Low limits over high limits - if ($chip == 2) { - $llo -= 256 if ($llo & 0x80); - $rlo -= 256 if ($rlo & 0x80); - return if ($llo > $lhi) or ($rlo > $rhi); - } - return 3; - } - - return ($chip <= 3) ? 7 : 5; -} - -# Chip to detect: 0 = MAX1668, 1 = MAX1805, 2 = MAX1989 -# Registers used: -# 0xfe: Company ID -# 0xff: Device ID -sub max1668_detect -{ - my ($file, $addr, $chip) = @_; - my $man_id = i2c_smbus_read_byte_data($file, 0xfe); - my $dev_id = i2c_smbus_read_byte_data($file, 0xff); - - return if $man_id != 0x4d; - return if $chip == 0 and $dev_id != 0x03; - return if $chip == 1 and $dev_id != 0x05; - return if $chip == 2 and $dev_id != 0x0b; - - return 7; -} - -# Chip to detect: 0 = MAX1619, 1 = MAX1618 -# Registers used: -# 0xfe: Company ID -# 0xff: Device ID -# 0x02: Status -# 0x03: Configuration -# 0x04: Conversion rate -sub max1619_detect -{ - my ($file, $addr, $chip) = @_; - my $man_id = i2c_smbus_read_byte_data($file, 0xfe); - my $dev_id = i2c_smbus_read_byte_data($file, 0xff); - my $conf = i2c_smbus_read_byte_data($file, 0x03); - my $status = i2c_smbus_read_byte_data($file, 0x02); - my $convrate = i2c_smbus_read_byte_data($file, 0x04); - - return if $man_id != 0x4D; # Maxim - - if ($chip == 0) { # MAX1619 - return if $dev_id != 0x04 - or ($conf & 0x03) - or ($status & 0x61) - or $convrate >= 8; - } - if ($chip == 1) { # MAX1618 - return if $dev_id != 0x02 - or ($conf & 0x07) - or ($status & 0x63); - } - - return 7; -} - -# Registers used: -# 0x28: User ID -# 0x29: User ID2 -sub ite_overclock_detect -{ - my ($file, $addr) = @_; - - my $uid1 = i2c_smbus_read_byte_data($file, 0x28); - my $uid2 = i2c_smbus_read_byte_data($file, 0x29); - return if $uid1 != 0x83 || $uid2 != 0x12; - - return 6; -} - -# Registers used: -# 0x00: Configuration -# 0x48: Full I2C Address -# 0x58: Mfr ID -# 0x5b: Device ID -sub it8712_i2c_detect -{ - my ($file, $addr) = @_; - my $reg; - return unless i2c_smbus_read_byte_data($file, 0x48) == $addr; - return unless (i2c_smbus_read_byte_data($file, 0x00) & 0x90) == 0x10; - return unless i2c_smbus_read_byte_data($file, 0x58) == 0x90; - return if i2c_smbus_read_byte_data($file, 0x5b) != 0x12; - return 7 + ($addr == 0x2d); -} - -# Registers used: -# 0-63: SPD Data and Checksum -sub eeprom_detect -{ - my ($file, $addr) = @_; - my $checksum = 0; - - # Check the checksum for validity (works for most DIMMs and RIMMs) - for (my $i = 0; $i <= 62; $i++) { - $checksum += i2c_smbus_read_byte_data($file, $i); - } - $checksum &= 255; - - return 8 if $checksum == i2c_smbus_read_byte_data($file, 63); - return; -} - -# Registers used: -# 0x00..0x07: DDC signature -sub ddcmonitor_detect -{ - my ($file, $addr) = @_; - - return unless - i2c_smbus_read_byte_data($file, 0x00) == 0x00 and - i2c_smbus_read_byte_data($file, 0x01) == 0xFF and - i2c_smbus_read_byte_data($file, 0x02) == 0xFF and - i2c_smbus_read_byte_data($file, 0x03) == 0xFF and - i2c_smbus_read_byte_data($file, 0x04) == 0xFF and - i2c_smbus_read_byte_data($file, 0x05) == 0xFF and - i2c_smbus_read_byte_data($file, 0x06) == 0xFF and - i2c_smbus_read_byte_data($file, 0x07) == 0x00; - - return 8; -} - -# Chip to detect: 0 = Poseidon I, 1 = Poseidon II, 2 = Scylla, -# 3 = Hermes, 4 = Heimdal, 5 = Heracles -# Registers used: -# 0x00-0x02: Identification (3 capital ASCII letters) -sub fsc_detect -{ - my ($file, $addr, $chip) = @_; - my $id; - - $id = chr(i2c_smbus_read_byte_data($file, 0x00)) - . chr(i2c_smbus_read_byte_data($file, 0x01)) - . chr(i2c_smbus_read_byte_data($file, 0x02)); - - return if $chip == 0 and $id ne 'PEG'; # Pegasus? aka Poseidon I - return if $chip == 1 and $id ne 'POS'; # Poseidon II - return if $chip == 2 and $id ne 'SCY'; # Scylla - return if $chip == 3 and $id ne 'HER'; # Hermes - return if $chip == 4 and $id ne 'HMD'; # Heimdal - return if $chip == 5 and $id ne 'HRC'; # Heracles - return if $chip == 6 and $id ne 'HDS'; # Hades - return if $chip == 7 and $id ne 'SYL'; # Syleus - - return 8; -} - -# Registers used: -# 0x3E: Manufacturer ID -# 0x3F: Version/Stepping -sub lm93_detect -{ - my ($file, $addr) = @_; - return unless i2c_smbus_read_byte_data($file, 0x3E) == 0x01 - and i2c_smbus_read_byte_data($file, 0x3F) == 0x73; - return 5; -} - -# Registers used: -# 0x3F: Revision ID -# 0x48: Address -# 0x4A, 0x4B, 0x4F, 0x57, 0x58: Reserved bits. -# We do not use 0x49's reserved bits on purpose. The register is named -# "VID4/Device ID" so it is doubtful bits 7-1 are really unused. -sub m5879_detect -{ - my ($file, $addr) = @_; - - return unless i2c_smbus_read_byte_data($file, 0x3F) == 0x01; - return unless i2c_smbus_read_byte_data($file, 0x48) == $addr; - - return unless (i2c_smbus_read_byte_data($file, 0x4A) & 0x06) == 0 - and (i2c_smbus_read_byte_data($file, 0x4B) & 0xFC) == 0 - and (i2c_smbus_read_byte_data($file, 0x4F) & 0xFC) == 0 - and (i2c_smbus_read_byte_data($file, 0x57) & 0xFE) == 0 - and (i2c_smbus_read_byte_data($file, 0x58) & 0xEF) == 0; - - return 7; -} - -# Registers used: -# 0x3E: Manufacturer ID -# 0x3F: Version/Stepping -# 0x47: VID (3 reserved bits) -# 0x49: VID4 (7 reserved bits) -sub smsc47m192_detect -{ - my ($file, $addr) = @_; - return unless i2c_smbus_read_byte_data($file, 0x3E) == 0x55 - and (i2c_smbus_read_byte_data($file, 0x3F) & 0xF0) == 0x20 - and (i2c_smbus_read_byte_data($file, 0x47) & 0x70) == 0x00 - and (i2c_smbus_read_byte_data($file, 0x49) & 0xFE) == 0x80; - return ($addr == 0x2d ? 6 : 5); -} - -# Chip to detect: 1 = DME1737, 2 = SCH5027 -# Registers used: -# 0x3E: Manufacturer ID -# 0x3F: Version/Stepping -# 0x73: Read-only test register (4 test bits) -# 0x8A: Read-only test register (7 test bits) -# 0xBA: Read-only test register (8 test bits) -sub dme1737_detect -{ - my ($file, $addr, $chip) = @_; - my $vendor = i2c_smbus_read_byte_data($file, 0x3E); - my $verstep = i2c_smbus_read_byte_data($file, 0x3F); - - return unless $vendor == 0x5C; # SMSC - - if ($chip == 1) { # DME1737 - return unless ($verstep & 0xF8) == 0x88 and - (i2c_smbus_read_byte_data($file, 0x73) & 0x0F) == 0x09 and - (i2c_smbus_read_byte_data($file, 0x8A) & 0x7F) == 0x4D; - } elsif ($chip == 2) { # SCH5027 - return unless $verstep >= 0x69 and $verstep <= 0x6F and - i2c_smbus_read_byte_data($file, 0xBA) == 0x0F; - } - - return ($addr == 0x2e ? 6 : 5); -} - -# Chip to detect: 1 = F75111R/RG/N, 2 = F75121R/F75122R/RG, 3 = F75373S/SG, -# 4 = F75375S/SP, 5 = F75387SG/RG, 6 = F75383M/S/F75384M/S, -# 7 = custom power control IC -# Registers used: -# 0x5A-0x5B: Chip ID -# 0x5D-0x5E: Vendor ID -sub fintek_detect -{ - my ($file, $addr, $chip) = @_; - my $chipid = (i2c_smbus_read_byte_data($file, 0x5A) << 8) - | i2c_smbus_read_byte_data($file, 0x5B); - my $vendid = (i2c_smbus_read_byte_data($file, 0x5D) << 8) - | i2c_smbus_read_byte_data($file, 0x5E); - - return unless $vendid == 0x1934; # Fintek ID - - if ($chip == 1) { # F75111R/RG/N - return unless $chipid == 0x0300; - } elsif ($chip == 2) { # F75121R/F75122R/RG - return unless $chipid == 0x0301; - } elsif ($chip == 3) { # F75373S/SG - return unless $chipid == 0x0204; - } elsif ($chip == 4) { # F75375S/SP - return unless $chipid == 0x0306; - } elsif ($chip == 5) { # F75387SG/RG - return unless $chipid == 0x0410; - } elsif ($chip == 6) { # F75383M/S/F75384M/S - # The datasheet has 0x0303, but Fintek say 0x0413 is also - # possible - return unless $chipid == 0x0303 || $chipid == 0x0413; - } elsif ($chip == 7) { # custom power control IC - return unless $chipid == 0x0302; - } - - return 7; -} - -# This checks for non-FFFF values for temperature, voltage, and current. -# The address (0x0b) is specified by the SMBus standard so it's likely -# that this really is a smart battery. -sub smartbatt_detect -{ - my ($file, $addr) = @_; - - return if i2c_smbus_read_word_data($file, 0x08) == 0xffff - || i2c_smbus_read_word_data($file, 0x09) == 0xffff - || i2c_smbus_read_word_data($file, 0x0a) == 0xffff; - return 5; -} - -# Chip to detect: 0 = W83L784R/AR/G, 1 = W83L785R/G, 2 = W83L786NR/NG/R/G, -# 3 = W83L785TS-S -# Registers used: -# 0x40: Configuration -# 0x4a: Full I2C Address (W83L784R only) -# 0x4b: I2C addresses of emulated LM75 chips (W83L784R only) -# 0x4c: Winbond Vendor ID (Low Byte) -# 0x4d: Winbond Vendor ID (High Byte) -# 0x4e: Chip ID -sub w83l784r_detect -{ - my ($file, $addr, $chip) = @_; - my ($reg, @res); - - return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00; - return if $chip == 0 - and i2c_smbus_read_byte_data($file, 0x4a) != $addr; - return unless i2c_smbus_read_byte_data($file, 0x4c) == 0xa3; - return unless i2c_smbus_read_byte_data($file, 0x4d) == 0x5c; - - $reg = i2c_smbus_read_byte_data($file, 0x4e); - return if $chip == 0 and $reg != 0x50; - return if $chip == 1 and $reg != 0x60; - return if $chip == 2 and $reg != 0x80; - return if $chip == 3 and $reg != 0x70; - - return 8 if $chip != 0; # No subclients - - @res = (8); - $reg = i2c_smbus_read_byte_data($file, 0x4b); - push @res, ($reg & 0x07) + 0x48 unless $reg & 0x08; - push @res, (($reg & 0x70) >> 4) + 0x48 unless $reg & 0x80; - return @res; -} - -# The max6650 has no device ID register. However, a few registers have -# spare bits, which are documented as being always zero on read. We read -# all of these registers check the spare bits. Any non-zero means this -# is not a max6650/1. -# -# The always zero bits are: -# configuration byte register (0x02) - top 2 bits -# gpio status register (0x14) - top 3 bits -# alarm enable register (0x08) - top 3 bits -# alarm status register (0x0A) - top 3 bits -# tachometer count time register (0x16) - top 6 bits -# Additionally, not all values are possible for lower 3 bits of -# the configuration register. -sub max6650_detect -{ - my ($file, $addr) = @_; - - my $conf = i2c_smbus_read_byte_data($file, 0x02); - - return if i2c_smbus_read_byte_data($file, 0x16) & 0xFC; - return if i2c_smbus_read_byte_data($file, 0x0A) & 0xE0; - return if i2c_smbus_read_byte_data($file, 0x08) & 0xE0; - return if i2c_smbus_read_byte_data($file, 0x14) & 0xE0; - return if ($conf & 0xC0) or ($conf & 0x07) > 4; - - return 2; -} - -sub max6655_detect -{ - my ($file, $addr) = @_; - - # checking RDID (Device ID) - return unless i2c_smbus_read_byte_data($file, 0xfe) == 0x0a; - # checking RDRV (Manufacturer ID) - return unless i2c_smbus_read_byte_data($file, 0xff) == 0x4d; - # checking unused bits (conversion rate, extended temperature) - return unless i2c_smbus_read_byte_data($file, 0x04) & 0xf8; - return unless i2c_smbus_read_byte_data($file, 0x10) & 0x1f; - return unless i2c_smbus_read_byte_data($file, 0x11) & 0x1f; - return unless i2c_smbus_read_byte_data($file, 0x12) & 0x1f; - - return 6; -} - -# This isn't very good detection. -# Verify the i2c address, and the stepping ID (which is 0xb0 on -# my chip but could be different for others... -sub vt1211_i2c_detect -{ - my ($file, $addr) = @_; - return unless (i2c_smbus_read_byte_data($file, 0x48) & 0x7f) == $addr; - return unless i2c_smbus_read_byte_data($file, 0x3f) == 0xb0; - return 2; -} - -# All ISA detection functions below take at least 1 parameter: -# $_[0]: Address -# Some of these functions which can detect more than one type of device, -# take a second parameter: -# $_[1]: Chip to detect - -# Chip to detect: 0 = LM78, 2 = LM79 -sub lm78_isa_detect -{ - my ($addr, $chip) = @_; - my $val = inb($addr + 1); - return if inb($addr + 2) != $val or inb($addr + 3) != $val or - inb($addr + 7) != $val; - - $val = inb($addr + 5); - outb($addr + 5, ~$val & 0x7f); - if ((inb($addr+5) & 0x7f) != (~ $val & 0x7f)) { - outb($addr+5, $val); - return; - } - - return unless (isa_read_i5d6($addr, 0x40) & 0x80) == 0x00; - my $reg = isa_read_i5d6($addr, 0x49); - return if $chip == 0 && ($reg != 0x00 && $reg != 0x20 && $reg != 0x40); - return if $chip == 2 && ($reg & 0xfe) != 0xc0; - - # Explicitly prevent misdetection of Winbond chips - $reg = isa_read_i5d6($addr, 0x4f); - return if $reg == 0xa3 || $reg == 0x5c; - - # Explicitly prevent misdetection of ITE chips - $reg = isa_read_i5d6($addr, 0x58); - return if $reg == 0x90; - - return 6; -} - -# Chip to detect: 0 = W83781D, 1 = W83782D -sub w83781d_isa_detect -{ - my ($addr, $chip) = @_; - my ($reg1, $reg2); - my $val = inb($addr + 1); - return if inb($addr + 2) != $val or inb($addr + 3) != $val or - inb($addr + 7) != $val; - - $val = inb($addr + 5); - outb($addr+5, ~$val & 0x7f); - if ((inb($addr+5) & 0x7f) != (~ $val & 0x7f)) { - outb($addr+5, $val); - return; - } - - $reg1 = isa_read_i5d6($addr, 0x4e); - $reg2 = isa_read_i5d6($addr, 0x4f); - return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or - (($reg1 & 0x80) == 0x80 and $reg2 == 0x5c); - return unless ($reg1 & 0x07) == 0x00; - $reg1 = isa_read_i5d6($addr, 0x58); - return if $chip == 0 && ($reg1 & 0xfe) != 0x10; - return if $chip == 1 && ($reg1 & 0xfe) != 0x30; - - return 8; -} - -######## -# IPMI # -######## - -# Returns: number of IPMI interfaces found -sub ipmi_from_smbios -{ - my ($version, $if, @ipmi_if); - - return 0 unless check_dmidecode_version(); - - # Parse the output of dmidecode into an array of IPMI interfaces. - # Each entry is a hash with the following keys: type and addr. - $if = -1; - open(local *DMIDECODE, "dmidecode -t 38 2>/dev/null |") or return 0; - while () { - if (m/^IPMI Device Information/) { - $if++; - next; - } - next unless $if >= 0; - - if (m/^\tInterface Type: (.*)$/) { - $ipmi_if[$if]->{type} = "IPMI BMC $1"; - $ipmi_if[$if]->{type} =~ s/ \(.*//; - next; - } - if (m/^\tBase Address: (0x[0-9A-Fa-f]+) \(I\/O\)$/) { - $ipmi_if[$if]->{addr} = oct($1); - next; - } - } - close(DMIDECODE); - - foreach $if (@ipmi_if) { - if (exists $if->{addr}) { - printf("\%-60s", sprintf("Found `\%s' at 0x\%x... ", - $if->{type}, $if->{addr})); - } else { - printf("\%-60s", sprintf("Found `\%s'... ", - $if->{type})); - } - print "Success!\n". - " (confidence 8, driver `ipmisensors')\n"; - my $new_hash = { - conf => 8, - isa_addr => $if->{addr} || 0, - chipname => $if->{type}, - }; - add_isa_to_chips_detected("ipmisensors", $new_hash); - } - - return scalar @ipmi_if; -} - -# We simply look for a register at standard locations. -# For KCS, use the STATUS register. For SMIC, use the FLAGS register. -# Incidentally they live at the same offset. -sub ipmi_detect -{ - my ($addr) = @_; - return if inb($addr + 3) == 0xff; - return 4; -} - -################### -# ALIAS DETECTION # -################### - -# These functions take at least 3 parameters: -# $_[0]: ISA/LPC address -# $_[1]: I2C file handle -# $_[2]: I2C address -# Some of these functions may take extra parameters. -# They return 1 if both devices are the same, 0 if not. - -# Extra parameters: -# $_[3]: First limit register to compare -# $_[4]: Last limit register to compare -sub winbond_alias_detect -{ - my ($isa_addr, $file, $i2c_addr, $first, $last) = @_; - my $i; - - return 0 unless isa_read_i5d6($isa_addr, 0x48) == $i2c_addr; - for ($i = $first; $i <= $last; $i++) { - return 0 unless isa_read_i5d6($isa_addr, $i) == - i2c_smbus_read_byte_data($file, $i); - } - return 1; -} - -############################ -# PCI CHIP / CPU DETECTION # -############################ - -sub sis5595_pci_detect -{ - return unless exists $pci_list{'1039:0008'}; - return 9; -} - -sub via686a_pci_detect -{ - return unless exists $pci_list{'1106:3057'}; - return 9; -} - -sub via8231_pci_detect -{ - return unless exists $pci_list{'1106:8235'}; - return 9; -} - -sub k8temp_pci_detect -{ - return unless exists $pci_list{'1022:1103'}; - return 9; -} - -sub fam11h_pci_detect -{ - return unless exists $pci_list{'1022:1303'}; - return 9; -} - -sub intel_amb_detect -{ - if ((exists $pci_list{'8086:25f0'}) || # Intel 5000 - (exists $pci_list{'8086:4030'})) { # Intel 5400 - return 9; - } - return; -} - -sub coretemp_detect -{ - my $probecpu; - foreach $probecpu (@cpu) { - if ($probecpu->{vendor_id} eq 'GenuineIntel' && - $probecpu->{'cpu family'} == 6 && - ($probecpu->{model} == 14 || # Pentium M DC - $probecpu->{model} == 15 || # Core 2 DC 65nm - $probecpu->{model} == 0x16 || # Core 2 SC 65nm - $probecpu->{model} == 0x17 || # Penryn 45nm - $probecpu->{model} == 0x1a || # Nehalem - $probecpu->{model} == 0x1c)) { # Atom - return 9; - } - } - return; -} - -sub c7temp_detect -{ - my $probecpu; - foreach $probecpu (@cpu) { - if ($probecpu->{vendor_id} eq 'CentaurHauls' && - $probecpu->{'cpu family'} == 6 && - ($probecpu->{model} == 0xa || - $probecpu->{model} == 0xd)) { - return 9; - } - } - return; -} - -################# -# SPECIAL MODES # -################# - -sub show_i2c_stats -{ - my ($chip, $addr, %histo, $chips); - - # Gather the data - foreach $chip (@chip_ids) { - next unless defined $chip->{i2c_addrs}; - $chips++; - foreach my $addr (@{$chip->{i2c_addrs}}) { - $histo{$addr}++; - } - } - - # Display the data - printf "\%d I2C chips known, \%d I2C addresses probed\n\n", - $chips, scalar keys %histo; - print " 0 1 2 3 4 5 6 7 8 9 a b c d e f\n". - "00: "; - for (my $addr = 0x03; $addr <= 0x77; $addr++) { - printf("\n\%02x:", $addr) if ($addr % 16) == 0; - if (defined $histo{$addr}) { - printf ' %02d', $histo{$addr}; - } else { - print ' --'; - } - } - print "\n"; -} - -################ -# MAIN PROGRAM # -################ - -# $_[0]: reference to a list of chip hashes -sub print_chips_report -{ - my ($listref) = @_; - my $data; - - foreach $data (@$listref) { - my $is_i2c = exists $data->{i2c_addr}; - my $is_isa = exists $data->{isa_addr}; - print " * "; - if ($is_i2c) { - printf "Bus `%s'\n", $i2c_adapters[$data->{i2c_devnr}]->{name}; - printf " Busdriver `%s', I2C address 0x%02x", - $i2c_adapters[$data->{i2c_devnr}]->{driver}, $data->{i2c_addr}; - if (exists $data->{i2c_sub_addrs}) { - print " (and"; - my $sub_addr; - foreach $sub_addr (@{$data->{i2c_sub_addrs}}) { - printf " 0x%02x", $sub_addr; - } - print ")" - } - print "\n "; - } - if ($is_isa) { - print "ISA bus"; - if ($data->{isa_addr}) { - printf ", address 0x%x", $data->{isa_addr}; - } - print " (Busdriver `i2c-isa')" - unless kernel_version_at_least(2, 6, 18); - print "\n "; - } - printf "Chip `%s' (confidence: %d)\n", - $data->{chipname}, $data->{conf}; - } -} - -sub generate_modprobes -{ - my ($driver, $detection, $adap); - my ($configfile, %bus_modules, %hwmon_modules); - - foreach $driver (keys %chips_detected) { - foreach $detection (@{$chips_detected{$driver}}) { - # Tag adapters which host hardware monitoring chips we want to access - if (exists $detection->{i2c_devnr} - && !exists $detection->{isa_addr}) { - $i2c_adapters[$detection->{i2c_devnr}]->{used}++; - } - - # i2c-isa is loaded automatically (as a dependency) - # since 2.6.14, and will soon be gone. - if (exists $detection->{isa_addr} - && !kernel_version_at_least(2, 6, 18)) { - $bus_modules{"i2c-isa"}++ - } - } - if ($driver eq "ipmisensors") { - $bus_modules{"ipmi-si"}++; - } - } - - # Handle aliases - # As of kernel 2.6.28, alias detection is handled by kernel drivers - # directly, so module options are no longer needed. - unless (kernel_version_at_least(2, 6, 28)) { - foreach $driver (keys %chips_detected) { - my @optionlist = (); - foreach $detection (@{$chips_detected{$driver}}) { - next unless exists $detection->{i2c_addr} - && exists $detection->{isa_addr} - && $i2c_adapters[$detection->{i2c_devnr}]->{used}; - - push @optionlist, sprintf("%d,0x%02x", - $detection->{i2c_devnr}, - $detection->{i2c_addr}); - } - - next if not @optionlist; - $configfile = "# hwmon module options\n" - unless defined $configfile; - $configfile .= "options $driver ignore=". - (join ",", @optionlist)."\n"; - } - } - - # If we added any module option to handle aliases, we need to load all - # the adapter drivers so that the numbers will be the same. If not, then - # we only load the adapter drivers which are useful. - foreach $adap (@i2c_adapters) { - next if $adap->{autoload}; - next if $adap->{driver} eq 'UNKNOWN'; - next if not defined $configfile and not $adap->{used}; - $bus_modules{$adap->{driver}}++; - } - - # Now determine the chip probe lines - foreach $driver (keys %chips_detected) { - next if not @{$chips_detected{$driver}}; - 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 { - open(local *INPUTFILE, "modprobe -l $driver 2>/dev/null |"); - local $_; - my $modulefound = 0; - while () { - if (m@/@) { - $modulefound = 1; - last; - } - } - close(INPUTFILE); - # Check return value from modprobe in case modprobe -l - # 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". - "driver availability.\n\n"; - } else { - $hwmon_modules{$driver}++ - unless hwmon_is_autoloaded($driver); - } - } - } - - my @bus_modules = sort keys %bus_modules; - my @hwmon_modules = sort keys %hwmon_modules; - return ($configfile, \@bus_modules, \@hwmon_modules); -} - -sub write_config -{ - my ($configfile, $bus_modules, $hwmon_modules) = @_; - - if (defined $configfile) { - my $have_modprobe_d = -d '/etc/modprobe.d'; - 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'); - $_ = ; - if (($have_modprobe_d and not m/^\s*n/i) or m/^\s*y/i) { - unless ($have_modprobe_d) { - mkdir('/etc/modprobe.d', 0777) - or die "Sorry, can't create /etc/modprobe.d ($!)"; - } - open(local *MODPROBE_D, ">/etc/modprobe.d/lm_sensors.conf") - or die "Sorry, can't create /etc/modprobe.d/lm_sensors.conf ($!)"; - print MODPROBE_D "# Generated by sensors-detect on " . scalar localtime() . "\n"; - print MODPROBE_D $configfile; - close(MODPROBE_D); - } else { - print "To make the sensors modules behave correctly, add these lines to\n". - "/etc/modprobe.conf:\n\n"; - print "#----cut here----\n". - $configfile. - "#----cut here----\n\n"; - } - } - - my $have_sysconfig = -d '/etc/sysconfig'; - printf "Do you want to \%s /etc/sysconfig/lm_sensors? (\%s): ", - (-e '/etc/sysconfig/lm_sensors' ? 'overwrite' : 'generate'), - ($have_sysconfig ? 'YES/no' : 'yes/NO'); - $_ = ; - if (($have_sysconfig and not m/^\s*n/i) or m/^\s*y/i) { - unless ($have_sysconfig) { - mkdir('/etc/sysconfig', 0777) - or die "Sorry, can't create /etc/sysconfig ($!)"; - } - open(local *SYSCONFIG, ">/etc/sysconfig/lm_sensors") - or die "Sorry, can't create /etc/sysconfig/lm_sensors ($!)"; - print SYSCONFIG "# Generated by sensors-detect on " . scalar localtime() . "\n"; - print SYSCONFIG <<'EOT'; -# This file is sourced by /etc/init.d/lm_sensors and defines the modules to -# be loaded/unloaded. -# -# The format of this file is a shell script that simply defines variables: -# HWMON_MODULES for hardware monitoring driver modules, and optionally -# BUS_MODULES for any required bus driver module (for example for I2C or SPI). - -EOT - print SYSCONFIG "BUS_MODULES=\"", join(" ", @{$bus_modules}), "\"\n" - if @{$bus_modules}; - print SYSCONFIG "HWMON_MODULES=\"", join(" ", @{$hwmon_modules}), "\"\n"; - - print SYSCONFIG <<'EOT'; - -# For compatibility reasons, modules are also listed individually as variables -# MODULE_0, MODULE_1, MODULE_2, etc. -# You should use BUS_MODULES and HWMON_MODULES instead if possible. - -EOT - my $i = 0; - foreach (@{$bus_modules}, @{$hwmon_modules}) { - print SYSCONFIG "MODULE_$i=$_\n"; - $i++; - } - close(SYSCONFIG); - - print "Copy prog/init/lm_sensors.init to /etc/init.d/lm_sensors\n". - "for initialization at boot time.\n" - unless -f "/etc/init.d/lm_sensors"; - - if (-x "/sbin/insserv" && -f "/etc/init.d/lm_sensors") { - system("/sbin/insserv", "/etc/init.d/lm_sensors"); - } elsif (-x "/sbin/chkconfig" && -f "/etc/init.d/lm_sensors") { - system("/sbin/chkconfig", "lm_sensors", "on"); - if (-x "/sbin/service") { - system("/sbin/service", "lm_sensors", "start"); - } - } else { - print "You should now start the lm_sensors service to load the required\n". - "kernel modules.\n\n"; - } - } else { - print "To load everything that is needed, add this to one of the system\n". - "initialization scripts (e.g. /etc/rc.d/rc.local):\n\n"; - print "#----cut here----\n"; - if (@{$bus_modules}) { - print "# Adapter drivers\n"; - print "modprobe $_\n" foreach (@{$bus_modules}); - } - print "# Chip drivers\n"; - print "modprobe $_\n" foreach (@{$hwmon_modules}); - print((-e '/usr/bin/sensors' ? - "/usr/bin/sensors -s\n" : - "/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". - "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") { - show_i2c_stats(); - exit 0; - } - - # We won't go very far if not root - unless ($> == 0) { - print "You need to be root to run this script.\n"; - exit -1; - } - - if (-x "/sbin/service" && -f "/etc/init.d/lm_sensors" && - -f "/var/lock/subsys/lm_sensors") { - system("/sbin/service", "lm_sensors", "stop"); - } - - initialize_kernel_version(); - initialize_conf(); - initialize_pci(); - initialize_modules_list(); - # Make sure any special case chips are added to the chip_ids list - # before making the support modules list - chip_special_cases(); - initialize_modules_supported(); - initialize_cpu_list(); - - print "# sensors-detect revision $revision\n"; - 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"; - - 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 ( =~ /^\s*n/i) { - $| = 1; - foreach my $entry (@cpu_ids) { - scan_cpu($entry); - } - $| = 0; - } - print "\n"; - - $superio_features = 0; - # Skip "random" I/O port probing on PPC - if ($kernel_arch ne 'ppc' - && $kernel_arch ne 'ppc64') { - 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 ( =~ /^\s*n/i) { - initialize_ioports(); - $superio_features |= scan_superio(0x2e, 0x2f); - $superio_features |= scan_superio(0x4e, 0x4f); - close_ioports(); - } - print "\n"; - - unless (is_laptop()) { - print "Some systems (mainly servers) implement IPMI, a set of common interfaces\n". - "through which system health data may be retrieved, amongst other things.\n". - "We first try to get the information from SMBIOS. If we don't find it\n". - "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 ( =~ /^\s*n/i) { - if (!ipmi_from_smbios()) { - initialize_ioports(); - scan_isa_bus(\@ipmi_ifs); - close_ioports(); - } - } - print "\n"; - } - - printf "Some hardware monitoring chips are accessible through the ISA I/O ports.\n". - "We have to write to arbitrary I/O ports to probe them. This is usually\n". - "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 = ; - unless ($input =~ /^\s*n/i - || ($superio_features && $input !~ /^\s*y/i)) { - initialize_ioports(); - scan_isa_bus(\@chip_ids); - close_ioports(); - } - print "\n"; - } - - print "Lastly, we can probe the I2C/SMBus adapters for connected hardware\n". - "monitoring devices. This is the most risky part, and while it works\n". - "reasonably well on most systems, it has been reported to cause trouble\n". - "on some systems.\n". - "Do you want to probe the I2C/SMBus adapters now? (YES/no): "; - - unless ( =~ /^\s*n/i) { - adapter_pci_detection(); - load_module("i2c-dev") unless -e "$sysfs_root/class/i2c-dev"; - initialize_i2c_adapters_list(); - $i2c_addresses_to_scan = i2c_addresses_to_scan(); - print "\n"; - - # Skip SMBus probing by default if Super-I/O has all the features - my $by_default = ~$superio_features & (FEAT_IN | FEAT_FAN | FEAT_TEMP); - # Except on Asus and Tyan boards which often have more than - # one hardware monitoring chip - $by_default = 1 if dmi_match('board_vendor', 'asustek', 'tyan', - 'supermicro'); - - for (my $dev_nr = 0; $dev_nr < @i2c_adapters; $dev_nr++) { - next unless exists $i2c_adapters[$dev_nr]; - scan_i2c_adapter($dev_nr, $by_default); - } - } - - if (!keys %chips_detected) { - print "Sorry, no sensors were detected.\n"; - if (is_laptop() && -d "$sysfs_root/firmware/acpi") { - print "This is relatively common on laptops, where thermal management is\n". - "handled by ACPI rather than the OS.\n"; - } else { - print "Either your system has no sensors, or they are not supported, or\n". - "they are connected to an I2C or SMBus adapter that is not\n". - "supported. If you find out what chips are on your board, check\n". - "http://www.lm-sensors.org/wiki/Devices for driver status.\n"; - } - exit; - } - - print "Now follows a summary of the probes I have just done.\n". - "Just press ENTER to continue: "; - ; - - initialize_hwmon_autoloaded(); - foreach my $driver (keys %chips_detected) { - next unless @{$chips_detected{$driver}}; - find_aliases($chips_detected{$driver}); - print "\nDriver `$driver'"; - print " (autoloaded)" if hwmon_is_autoloaded($driver); - print ":\n"; - print_chips_report($chips_detected{$driver}); - } - print "\n"; - - my ($configfile, $bus_modules, $hwmon_modules) = generate_modprobes(); - - if (@{$hwmon_modules}) { - write_config($configfile, $bus_modules, $hwmon_modules); - } else { - print "No modules to load, skipping modules configuration.\n\n"; - } - - unload_modules(); -} - -sub cleanup_on_int -{ - print "\n"; - unload_modules(); - exit; -} - -$SIG{INT} = \&cleanup_on_int; - -main; diff --git a/sources b/sources index f019311..618776c 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -613d7cfa23b70c0abae3fabb0a72ff5f lm_sensors-3.1.1.tar.bz2 +58a9a225808ac4587c4c8cbd12b40b5c lm_sensors-3.1.2.tar.bz2