2000-07-02 18:11:31 +00:00
|
|
|
#!/usr/bin/perl -w
|
1999-02-17 20:55:23 +00:00
|
|
|
#
|
2008-11-18 12:23:00 +00:00
|
|
|
# sensors-detect - Detect hardware monitoring chips
|
2004-03-20 09:29:50 +00:00
|
|
|
# Copyright (C) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>
|
2008-02-20 19:05:00 +00:00
|
|
|
# Copyright (C) 2004 - 2008 Jean Delvare <khali@linux-fr.org>
|
1999-02-17 20:55:23 +00:00
|
|
|
#
|
|
|
|
# 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
|
2008-03-26 13:37:12 +00:00
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
# MA 02110-1301 USA.
|
1999-02-17 20:55:23 +00:00
|
|
|
#
|
|
|
|
|
1999-03-10 01:17:15 +00:00
|
|
|
require 5.004;
|
|
|
|
|
1999-02-06 01:04:57 +00:00
|
|
|
use strict;
|
2002-11-08 09:38:29 +00:00
|
|
|
use Fcntl;
|
|
|
|
use POSIX;
|
2006-07-29 15:58:26 +00:00
|
|
|
use File::Basename;
|
1999-02-06 01:04:57 +00:00
|
|
|
|
2007-06-26 07:47:30 +00:00
|
|
|
# We will call modprobe, which typically lives in either /sbin,
|
2007-04-20 13:38:59 +00:00
|
|
|
# /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/(^|:)$_\/?(:|$)/;
|
|
|
|
}
|
2003-08-05 09:08:38 +00:00
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
#########################
|
|
|
|
# CONSTANT DECLARATIONS #
|
|
|
|
#########################
|
|
|
|
|
2008-05-28 07:26:11 +00:00
|
|
|
use constant NO_CACHE => 1;
|
2008-11-30 09:09:04 +00:00
|
|
|
use vars qw(@pci_adapters @chip_ids @non_hwmon_chip_ids $i2c_addresses_to_scan
|
2008-11-30 09:54:19 +00:00
|
|
|
$revision @i2c_byte_cache);
|
2005-07-18 19:00:49 +00:00
|
|
|
|
|
|
|
$revision = '$Revision$ ($Date$)';
|
2005-07-19 09:12:18 +00:00
|
|
|
$revision =~ s/\$\w+: (.*?) \$/$1/g;
|
2006-09-01 16:45:50 +00:00
|
|
|
$revision =~ s/ \([^()]*\)//;
|
1999-02-18 00:19:19 +00:00
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
# 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.
|
2006-08-28 11:13:31 +00:00
|
|
|
# Each entry must have a vendid (Vendor ID), devid (Device ID) and
|
2008-11-24 13:34:30 +00:00
|
|
|
# procid (Device name) and driver (Device driver).
|
2008-05-22 12:01:33 +00:00
|
|
|
@pci_adapters = (
|
2008-11-29 20:12:58 +00:00
|
|
|
{
|
|
|
|
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 => 0x0630,
|
|
|
|
procid => "Silicon Integrated Systems SIS630",
|
|
|
|
driver => "i2c-sis630",
|
|
|
|
}, {
|
|
|
|
vendid => 0x1039,
|
|
|
|
devid => 0x0730,
|
|
|
|
procid => "Silicon Integrated Systems SIS730",
|
|
|
|
driver => "i2c-sis630",
|
|
|
|
}, {
|
|
|
|
# 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 nForce4 SMBus (MCP51)",
|
|
|
|
driver => "i2c-nforce2",
|
|
|
|
}, {
|
|
|
|
vendid => 0x10de,
|
|
|
|
devid => 0x0368,
|
|
|
|
procid => "nVidia Corporation nForce4 SMBus (MCP55)",
|
|
|
|
driver => "i2c-nforce2",
|
|
|
|
}, {
|
|
|
|
vendid => 0x10de,
|
|
|
|
devid => 0x03eb,
|
|
|
|
procid => "nVidia Corporation nForce4 SMBus (MCP61)",
|
|
|
|
driver => "i2c-nforce2",
|
|
|
|
}, {
|
|
|
|
vendid => 0x10de,
|
|
|
|
devid => 0x0446,
|
|
|
|
procid => "nVidia Corporation nForce4 SMBus (MCP65)",
|
|
|
|
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 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",
|
|
|
|
}
|
1999-02-17 20:55:23 +00:00
|
|
|
);
|
|
|
|
|
2004-03-15 04:23:54 +00:00
|
|
|
# The following entries used to appear directly in @pci_adapters.
|
|
|
|
# Because of the tendency of SiS chipsets to have their real PCI
|
|
|
|
# IDs obscured, we have to qualify these with a custom detection
|
|
|
|
# routine before we add them to the @pci_adapters list.
|
|
|
|
#
|
2008-11-22 15:52:52 +00:00
|
|
|
use vars qw(@pci_adapters_sis5595 @pci_adapters_sis96x);
|
2004-03-15 04:23:54 +00:00
|
|
|
@pci_adapters_sis5595 = (
|
2008-11-29 20:12:58 +00:00
|
|
|
{
|
|
|
|
vendid => 0x1039,
|
|
|
|
devid => 0x0008,
|
|
|
|
procid => "Silicon Integrated Systems SIS5595",
|
|
|
|
driver => "i2c-sis5595",
|
|
|
|
}
|
2004-03-15 04:23:54 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
@pci_adapters_sis96x = (
|
2008-11-29 20:12:58 +00:00
|
|
|
{
|
|
|
|
vendid => 0x1039,
|
|
|
|
devid => 0x0016,
|
|
|
|
procid => "Silicon Integrated Systems SMBus Controller",
|
|
|
|
driver => "i2c-sis96x",
|
|
|
|
}
|
2004-03-15 04:23:54 +00:00
|
|
|
);
|
|
|
|
|
2008-11-24 13:24:00 +00:00
|
|
|
# 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 /sys/class/i2c-adapter.
|
|
|
|
# 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 / },
|
2008-11-27 16:44:00 +00:00
|
|
|
{ driver => "scx200_acb", match => qr/^(NatSemi SCx200 ACCESS\.bus|SCx200 ACB\d+|CS553[56] ACB\d+)/ },
|
2008-11-24 13:24:00 +00:00
|
|
|
);
|
|
|
|
|
2008-11-24 13:46:52 +00:00
|
|
|
# This is a list of all recognized I2C and ISA chips.
|
1999-02-22 20:40:16 +00:00
|
|
|
# Each entry must have the following fields:
|
|
|
|
# name: The full chip name
|
2008-11-24 13:46:52 +00:00
|
|
|
# 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.
|
1999-02-22 20:40:16 +00:00
|
|
|
# i2c_detect (optional): For I2C chips, the function to call to detect
|
2008-11-24 13:46:52 +00:00
|
|
|
# this chip. The function will be passed two parameters: an open file
|
1999-02-22 20:40:16 +00:00
|
|
|
# descriptor to access the bus, and the I2C address to probe.
|
2008-11-24 13:46:52 +00:00
|
|
|
# isa_addrs (optional): For ISA chips, the list of port addresses to
|
1999-02-23 14:14:32 +00:00
|
|
|
# probe.
|
1999-02-22 20:40:16 +00:00
|
|
|
# isa_detect (optional): For ISA chips, the function to call to detect
|
2008-11-24 13:46:52 +00:00
|
|
|
# this chip. The function will be passed one parameter: the ISA address
|
1999-02-23 14:14:32 +00:00
|
|
|
# to probe.
|
1999-02-23 20:28:05 +00:00
|
|
|
# alias_detect (optional): For chips which can be both on the ISA and the
|
2008-11-24 13:46:52 +00:00
|
|
|
# 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.
|
1999-02-18 00:19:19 +00:00
|
|
|
@chip_ids = (
|
2008-11-29 22:28:05 +00:00
|
|
|
{
|
|
|
|
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 => "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 => "to-be-written",
|
|
|
|
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 => "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",
|
2008-11-29 22:30:35 +00:00
|
|
|
i2c_addrs => [0x2c..0x2e],
|
2008-11-29 22:28:05 +00:00
|
|
|
i2c_detect => sub { andigilog_detect(@_, 1); },
|
|
|
|
}, {
|
|
|
|
name => "Andigilog aSC7621",
|
|
|
|
driver => "to-be-written",
|
2008-11-29 22:30:35 +00:00
|
|
|
i2c_addrs => [0x2c..0x2e],
|
2008-11-29 22:28:05 +00:00
|
|
|
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 => "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",
|
|
|
|
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",
|
2008-11-29 22:30:35 +00:00
|
|
|
i2c_addrs => [0x2c..0x2e],
|
2008-11-29 22:28:05 +00:00
|
|
|
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 => "to-be-written",
|
|
|
|
i2c_addrs => [0x4c..0x4e],
|
|
|
|
i2c_detect => sub { lm90_detect(@_, 10); },
|
|
|
|
}, {
|
|
|
|
name => "National Semiconductor LM95231",
|
|
|
|
driver => "to-be-written",
|
|
|
|
i2c_addrs => [0x2b, 0x19, 0x2a],
|
|
|
|
i2c_detect => sub { lm95231_detect(@_); },
|
|
|
|
}, {
|
|
|
|
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 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 => "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(@_); },
|
|
|
|
}, {
|
|
|
|
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(@_); },
|
|
|
|
}
|
2007-06-08 14:39:06 +00:00
|
|
|
);
|
2006-06-18 16:53:02 +00:00
|
|
|
|
2008-11-30 09:09:04 +00:00
|
|
|
# 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(@_); },
|
|
|
|
}
|
|
|
|
);
|
2007-10-19 13:29:56 +00:00
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
# This is a list of all recognized superio chips.
|
2002-12-09 03:01:23 +00:00
|
|
|
# Each entry must have the following fields:
|
|
|
|
# name: The full chip name
|
2008-11-24 13:57:39 +00:00
|
|
|
# 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)
|
2005-02-08 18:17:01 +00:00
|
|
|
# devid_mask (optional): Bitmask to apply before checking the device ID
|
2002-12-09 03:01:23 +00:00
|
|
|
# logdev: The logical device containing the sensors
|
2008-11-24 13:57:39 +00:00
|
|
|
# alias_detect (optional): For chips which can be both on the LPC and the
|
|
|
|
# I2C bus, a function which detects whether two entries are the same.
|
|
|
|
# The function will be passed three parameters: the LPC address, an
|
|
|
|
# open file descriptor to access the I2C bus, and the I2C address.
|
2008-11-30 09:38:34 +00:00
|
|
|
use vars qw(@superio_ids_natsemi @superio_ids_smsc @superio_ids_smsc_ns
|
|
|
|
@superio_ids_winbond @superio_ids_ite @superio_ids);
|
|
|
|
|
|
|
|
@superio_ids_natsemi = (
|
2008-11-30 09:49:11 +00:00
|
|
|
{
|
|
|
|
name => "Nat. Semi. PC8374L Super IO Sensors",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0xf1,
|
|
|
|
logdev => 0x08,
|
|
|
|
}, {
|
|
|
|
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,
|
|
|
|
}, {
|
|
|
|
name => "Nat. Semi. PC87363 Super IO Fan Sensors",
|
|
|
|
driver => "pc87360",
|
|
|
|
devid => 0xe8,
|
|
|
|
logdev => 0x09,
|
|
|
|
}, {
|
|
|
|
name => "Nat. Semi. PC87364 Super IO Fan Sensors",
|
|
|
|
driver => "pc87360",
|
|
|
|
devid => 0xe4,
|
|
|
|
logdev => 0x09,
|
|
|
|
}, {
|
|
|
|
name => "Nat. Semi. PC87365 Super IO Fan Sensors",
|
|
|
|
driver => "pc87360",
|
|
|
|
devid => 0xe5,
|
|
|
|
logdev => 0x09,
|
|
|
|
}, {
|
|
|
|
name => "Nat. Semi. PC87365 Super IO Voltage Sensors",
|
|
|
|
driver => "pc87360",
|
|
|
|
devid => 0xe5,
|
|
|
|
logdev => 0x0d,
|
|
|
|
}, {
|
|
|
|
name => "Nat. Semi. PC87365 Super IO Thermal Sensors",
|
|
|
|
driver => "pc87360",
|
|
|
|
devid => 0xe5,
|
|
|
|
logdev => 0x0e,
|
|
|
|
}, {
|
|
|
|
name => "Nat. Semi. PC87366 Super IO Fan Sensors",
|
|
|
|
driver => "pc87360",
|
|
|
|
devid => 0xe9,
|
|
|
|
logdev => 0x09,
|
|
|
|
}, {
|
|
|
|
name => "Nat. Semi. PC87366 Super IO Voltage Sensors",
|
|
|
|
driver => "pc87360",
|
|
|
|
devid => 0xe9,
|
|
|
|
logdev => 0x0d,
|
|
|
|
}, {
|
|
|
|
name => "Nat. Semi. PC87366 Super IO Thermal Sensors",
|
|
|
|
driver => "pc87360",
|
|
|
|
devid => 0xe9,
|
|
|
|
logdev => 0x0e,
|
|
|
|
}, {
|
|
|
|
name => "Nat. Semi. PC87372 Super IO Fan Sensors",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0xf0,
|
|
|
|
logdev => 0x09,
|
|
|
|
}, {
|
|
|
|
name => "Nat. Semi. PC87373 Super IO Fan Sensors",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0xf3,
|
|
|
|
logdev => 0x09,
|
|
|
|
}, {
|
|
|
|
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,
|
|
|
|
}, {
|
|
|
|
name => "Nat. Semi. PC87427 Super IO Health Sensors",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0xf2,
|
|
|
|
logdev => 0x14,
|
|
|
|
}
|
2008-11-30 09:38:34 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
@superio_ids_smsc = (
|
2008-11-30 09:49:11 +00:00
|
|
|
{
|
|
|
|
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,
|
|
|
|
}, {
|
|
|
|
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,
|
|
|
|
}, {
|
|
|
|
name => "SMSC LPC47B397-NC Super IO",
|
|
|
|
driver => "smsc47b397",
|
|
|
|
devid => 0x6f,
|
|
|
|
logdev => 0x08,
|
|
|
|
}, {
|
|
|
|
name => "SMSC LPC47M10x/112/13x Super IO Fan Sensors",
|
|
|
|
driver => "smsc47m1",
|
|
|
|
devid => 0x59,
|
|
|
|
logdev => 0x0a,
|
|
|
|
}, {
|
|
|
|
name => "SMSC LPC47M14x Super IO Fan Sensors",
|
|
|
|
driver => "smsc47m1",
|
|
|
|
devid => 0x5f,
|
|
|
|
logdev => 0x0a,
|
|
|
|
}, {
|
|
|
|
name => "SMSC LPC47M15x/192/997 Super IO Fan Sensors",
|
|
|
|
driver => "smsc47m1",
|
|
|
|
devid => 0x60,
|
|
|
|
logdev => 0x0a,
|
|
|
|
}, {
|
|
|
|
name => "SMSC LPC47M172 Super IO Fan Sensors",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0x14,
|
|
|
|
logdev => 0x0a,
|
|
|
|
}, {
|
|
|
|
name => "SMSC LPC47M182 Super IO Fan Sensors",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0x74,
|
|
|
|
logdev => 0x0a,
|
|
|
|
}, {
|
|
|
|
name => "SMSC LPC47M233 Super IO Sensors",
|
|
|
|
driver => "smsc47m1",
|
|
|
|
devid => 0x6b80,
|
|
|
|
devid_mask => 0xff80,
|
|
|
|
logdev => 0x0a,
|
|
|
|
}, {
|
|
|
|
name => "SMSC LPC47M292 Super IO Fan Sensors",
|
|
|
|
driver => "smsc47m1",
|
|
|
|
devid => 0x6b00,
|
|
|
|
devid_mask => 0xff80,
|
|
|
|
logdev => 0x0a,
|
|
|
|
}, {
|
|
|
|
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,
|
|
|
|
}, {
|
|
|
|
name => "SMSC LPC47S42x Super IO Fan Sensors",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0x57,
|
|
|
|
logdev => 0x0a,
|
|
|
|
}, {
|
|
|
|
name => "SMSC LPC47S45x Super IO Fan Sensors",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0x62,
|
|
|
|
logdev => 0x0a,
|
|
|
|
}, {
|
|
|
|
name => "SMSC LPC47U33x Super IO Fan Sensors",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0x54,
|
|
|
|
logdev => 0x0a,
|
|
|
|
}, {
|
|
|
|
name => "SMSC SCH3112 Super IO",
|
|
|
|
driver => "dme1737",
|
|
|
|
devid => 0x7c,
|
|
|
|
logdev => 0x0a,
|
|
|
|
}, {
|
|
|
|
name => "SMSC SCH3114 Super IO",
|
|
|
|
driver => "dme1737",
|
|
|
|
devid => 0x7d,
|
|
|
|
logdev => 0x0a,
|
|
|
|
}, {
|
|
|
|
name => "SMSC SCH3116 Super IO",
|
|
|
|
driver => "dme1737",
|
|
|
|
devid => 0x7f,
|
|
|
|
logdev => 0x0a,
|
|
|
|
}, {
|
|
|
|
name => "SMSC SCH4307 Super IO Fan Sensors",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0x90,
|
|
|
|
logdev => 0x08,
|
|
|
|
}, {
|
|
|
|
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,
|
|
|
|
}, {
|
|
|
|
name => "SMSC SCH5307-NS Super IO",
|
|
|
|
driver => "smsc47b397",
|
|
|
|
devid => 0x81,
|
|
|
|
logdev => 0x08,
|
|
|
|
}, {
|
|
|
|
name => "SMSC SCH5317 Super IO",
|
|
|
|
driver => "smsc47b397",
|
|
|
|
devid => 0x85,
|
|
|
|
logdev => 0x08,
|
|
|
|
}, {
|
|
|
|
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,
|
|
|
|
}, {
|
|
|
|
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,
|
|
|
|
}
|
2008-11-30 09:38:34 +00:00
|
|
|
);
|
|
|
|
|
2008-11-30 09:49:11 +00:00
|
|
|
# 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).
|
2008-11-30 09:38:34 +00:00
|
|
|
@superio_ids_smsc_ns = (
|
2008-11-30 09:49:11 +00:00
|
|
|
{
|
|
|
|
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,
|
|
|
|
}
|
2008-11-30 09:38:34 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
@superio_ids_winbond = (
|
2008-11-30 09:49:11 +00:00
|
|
|
{
|
|
|
|
name => "VIA VT1211 Super IO Sensors",
|
|
|
|
driver => "vt1211",
|
|
|
|
devid => 0x3c,
|
|
|
|
logdev => 0x0b,
|
|
|
|
alias_detect => sub { vt1211_alias_detect(@_); },
|
|
|
|
}, {
|
|
|
|
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,
|
|
|
|
alias_detect => sub { winbond_alias_detect(@_, 0x2b, 0x3d); },
|
|
|
|
}, {
|
|
|
|
name => "Winbond W83627THF/THG Super IO Sensors",
|
|
|
|
driver => "w83627hf",
|
|
|
|
devid => 0x82,
|
|
|
|
logdev => 0x0b,
|
|
|
|
}, {
|
|
|
|
name => "Winbond W83637HF/HG Super IO Sensors",
|
|
|
|
driver => "w83627hf",
|
|
|
|
devid => 0x70,
|
|
|
|
logdev => 0x0b,
|
|
|
|
}, {
|
|
|
|
name => "Winbond W83687THF Super IO Sensors",
|
|
|
|
driver => "w83627hf",
|
|
|
|
devid => 0x85,
|
|
|
|
logdev => 0x0b,
|
|
|
|
}, {
|
|
|
|
name => "Winbond W83697HF/F/HG Super IO Sensors",
|
|
|
|
driver => "w83627hf",
|
|
|
|
devid => 0x60,
|
|
|
|
logdev => 0x0b,
|
|
|
|
}, {
|
|
|
|
name => "Winbond W83697SF/UF/UG Super IO PWM",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0x68,
|
|
|
|
logdev => 0x0b,
|
|
|
|
}, {
|
|
|
|
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,
|
|
|
|
alias_detect => sub { winbond_alias_detect(@_, 0x2b, 0x3e); },
|
|
|
|
}, {
|
|
|
|
name => "Winbond W83627DHG Super IO Sensors",
|
|
|
|
driver => "w83627ehf",
|
|
|
|
devid => 0xA020,
|
|
|
|
devid_mask => 0xFFF0,
|
|
|
|
logdev => 0x0b,
|
|
|
|
alias_detect => sub { winbond_alias_detect(@_, 0x2b, 0x3e); },
|
|
|
|
}, {
|
|
|
|
name => "Winbond W83L517D Super IO",
|
|
|
|
driver => "not-a-sensor",
|
|
|
|
devid => 0x61,
|
|
|
|
}, {
|
|
|
|
name => "Fintek F71805F/FG Super IO Sensors",
|
|
|
|
driver => "f71805f",
|
|
|
|
devid => 0x0406,
|
|
|
|
logdev => 0x04,
|
|
|
|
}, {
|
|
|
|
name => "Fintek F71862FG Super IO Sensors",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0x0601,
|
|
|
|
logdev => 0x04,
|
|
|
|
}, {
|
|
|
|
name => "Fintek F71806FG/F71872FG Super IO Sensors",
|
|
|
|
driver => "f71805f",
|
|
|
|
devid => 0x0341,
|
|
|
|
logdev => 0x04,
|
|
|
|
}, {
|
|
|
|
name => "Fintek F71858DG Super IO Sensors",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0x0507,
|
|
|
|
logdev => 0x02,
|
|
|
|
}, {
|
|
|
|
name => "Fintek F71882FG/F71883FG Super IO Sensors",
|
|
|
|
driver => "f71882fg",
|
|
|
|
devid => 0x0541,
|
|
|
|
logdev => 0x04,
|
|
|
|
}, {
|
|
|
|
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 => "f8000",
|
|
|
|
devid => 0x0581,
|
|
|
|
logdev => 0x04,
|
|
|
|
}, {
|
|
|
|
# Shouldn't be in this family, but seems to be still.
|
|
|
|
name => "ITE IT8708F Super IO",
|
|
|
|
driver => "not-a-sensor",
|
|
|
|
devid => 0x8708,
|
|
|
|
}
|
2008-11-30 09:38:34 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
@superio_ids_ite = (
|
2008-11-30 09:49:11 +00:00
|
|
|
{
|
|
|
|
name => "ITE IT8702F Super IO Sensors",
|
|
|
|
driver => "to-be-written",
|
|
|
|
devid => 0x8702,
|
|
|
|
logdev => 0x04,
|
|
|
|
}, {
|
|
|
|
name => "ITE IT8705F Super IO Sensors",
|
|
|
|
driver => "it87",
|
|
|
|
devid => 0x8705,
|
|
|
|
logdev => 0x04,
|
|
|
|
}, {
|
|
|
|
name => "ITE IT8712F Super IO Sensors",
|
|
|
|
driver => "it87",
|
|
|
|
devid => 0x8712,
|
|
|
|
logdev => 0x04,
|
|
|
|
alias_detect => sub { winbond_alias_detect(@_, 0x30, 0x45); },
|
|
|
|
}, {
|
|
|
|
name => "ITE IT8716F Super IO Sensors",
|
|
|
|
driver => "it87",
|
|
|
|
devid => 0x8716,
|
|
|
|
logdev => 0x04,
|
|
|
|
}, {
|
|
|
|
name => "ITE IT8718F Super IO Sensors",
|
|
|
|
driver => "it87",
|
|
|
|
devid => 0x8718,
|
|
|
|
logdev => 0x04,
|
|
|
|
}, {
|
|
|
|
name => "ITE IT8720F Super IO Sensors",
|
|
|
|
driver => "it87",
|
|
|
|
devid => 0x8720,
|
|
|
|
logdev => 0x04,
|
|
|
|
}, {
|
|
|
|
name => "ITE IT8726F Super IO Sensors",
|
|
|
|
driver => "it87",
|
|
|
|
devid => 0x8726,
|
|
|
|
logdev => 0x04,
|
|
|
|
}
|
2008-11-30 09:38:34 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
# 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
|
2008-11-30 09:49:11 +00:00
|
|
|
# generic probing if we fail to recognize the chip.
|
2008-11-30 09:38:34 +00:00
|
|
|
# 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 = (
|
2008-11-30 09:49:11 +00:00
|
|
|
{
|
|
|
|
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/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,
|
|
|
|
}
|
2002-12-09 03:01:23 +00:00
|
|
|
);
|
1999-02-18 00:19:19 +00:00
|
|
|
|
2008-11-30 09:54:19 +00:00
|
|
|
# Drivers for bridge, CPU and memory embedded sensors
|
2006-10-15 09:30:45 +00:00
|
|
|
# Each entry must have the following fields:
|
2008-11-30 09:54:19 +00:00
|
|
|
# name: The device name
|
2006-10-15 09:30:45 +00:00
|
|
|
# driver: The driver name. Put "to-be-written" if no driver is available.
|
|
|
|
# detect: Detection callback function. No parameter will be passed to
|
2008-11-30 09:54:19 +00:00
|
|
|
# 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);
|
|
|
|
|
2006-10-15 09:30:45 +00:00
|
|
|
@cpu_ids = (
|
2008-11-30 09:54:19 +00:00
|
|
|
{
|
|
|
|
name => "Silicon Integrated Systems SIS5595",
|
|
|
|
driver => "sis5595",
|
2008-11-30 10:25:11 +00:00
|
|
|
detect => \&sis5595_pci_detect,
|
2008-11-30 09:54:19 +00:00
|
|
|
}, {
|
|
|
|
name => "VIA VT82C686 Integrated Sensors",
|
|
|
|
driver => "via686a",
|
2008-11-30 10:25:11 +00:00
|
|
|
detect => \&via686a_pci_detect,
|
2008-11-30 09:54:19 +00:00
|
|
|
}, {
|
|
|
|
name => "VIA VT8231 Integrated Sensors",
|
|
|
|
driver => "vt8231",
|
2008-11-30 10:25:11 +00:00
|
|
|
detect => \&via8231_pci_detect,
|
2008-11-30 09:54:19 +00:00
|
|
|
}, {
|
|
|
|
name => "AMD K8 thermal sensors",
|
|
|
|
driver => "k8temp",
|
2008-11-30 10:25:11 +00:00
|
|
|
detect => \&k8temp_pci_detect,
|
2008-11-30 09:54:19 +00:00
|
|
|
}, {
|
|
|
|
name => "AMD K10 thermal sensors",
|
|
|
|
driver => "to-be-written",
|
2008-11-30 10:25:11 +00:00
|
|
|
detect => \&k10temp_pci_detect,
|
2008-11-30 09:54:19 +00:00
|
|
|
}, {
|
|
|
|
name => "Intel Core family thermal sensor",
|
|
|
|
driver => "coretemp",
|
2008-11-30 10:25:11 +00:00
|
|
|
detect => \&coretemp_detect,
|
2008-11-30 09:54:19 +00:00
|
|
|
}, {
|
|
|
|
name => "Intel AMB FB-DIMM thermal sensor",
|
|
|
|
driver => "i5k_amb",
|
2008-11-30 10:25:11 +00:00
|
|
|
detect => \&intel_amb_detect,
|
2008-11-30 09:54:19 +00:00
|
|
|
}, {
|
|
|
|
name => "VIA C7 thermal and voltage sensors",
|
|
|
|
driver => "c7temp",
|
2008-11-30 10:25:11 +00:00
|
|
|
detect => \&c7temp_detect,
|
2008-11-30 09:54:19 +00:00
|
|
|
}
|
2006-10-15 09:30:45 +00:00
|
|
|
);
|
|
|
|
|
1999-02-18 00:19:19 +00:00
|
|
|
#######################
|
|
|
|
# AUXILIARY FUNCTIONS #
|
|
|
|
#######################
|
|
|
|
|
1999-02-18 18:09:14 +00:00
|
|
|
# $_[0] is the sought value
|
|
|
|
# @_[1..] is the list to seek in
|
2008-11-30 12:24:42 +00:00
|
|
|
# Returns: 1 if found, 0 if not.
|
1999-02-18 18:09:14 +00:00
|
|
|
sub contains
|
|
|
|
{
|
2008-11-30 12:24:42 +00:00
|
|
|
my $sought = shift;
|
|
|
|
local $_;
|
|
|
|
|
|
|
|
foreach (@_) {
|
|
|
|
return 1 if $sought eq $_;
|
|
|
|
}
|
|
|
|
return 0;
|
1999-02-18 18:09:14 +00:00
|
|
|
}
|
1999-02-18 00:19:19 +00:00
|
|
|
|
2008-05-09 17:59:51 +00:00
|
|
|
# Address can be decimal or hexadecimal
|
|
|
|
sub valid_address
|
|
|
|
{
|
2008-11-30 12:24:42 +00:00
|
|
|
my $value = shift;
|
2008-05-09 17:59:51 +00:00
|
|
|
|
2008-11-30 12:24:42 +00:00
|
|
|
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;
|
2008-05-09 17:59:51 +00:00
|
|
|
|
2008-11-30 12:24:42 +00:00
|
|
|
return $value;
|
2008-05-09 17:59:51 +00:00
|
|
|
}
|
|
|
|
|
1999-02-24 00:22:52 +00:00
|
|
|
sub parse_not_to_scan
|
|
|
|
{
|
2008-11-30 12:24:42 +00:00
|
|
|
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;
|
1999-02-24 00:22:52 +00:00
|
|
|
}
|
1999-02-19 01:52:29 +00:00
|
|
|
|
1999-02-28 17:41:46 +00:00
|
|
|
# @_[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
|
|
|
|
{
|
2008-11-30 12:24:42 +00:00
|
|
|
my ($list1, $list2) = @_;
|
|
|
|
my ($el1, $el2);
|
|
|
|
|
|
|
|
foreach $el1 (@$list1) {
|
|
|
|
foreach $el2 (@$list2) {
|
|
|
|
return 1 if $el1 == $el2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
1999-02-28 17:41:46 +00:00
|
|
|
}
|
|
|
|
|
1999-02-22 18:20:35 +00:00
|
|
|
###################
|
2008-11-27 18:27:20 +00:00
|
|
|
# I/O PORT ACCESS #
|
1999-02-22 18:20:35 +00:00
|
|
|
###################
|
|
|
|
|
1999-02-23 14:14:32 +00:00
|
|
|
sub initialize_ioports
|
1999-02-22 18:20:35 +00:00
|
|
|
{
|
2008-11-27 18:27:20 +00:00
|
|
|
sysopen(IOPORTS, "/dev/port", O_RDWR)
|
|
|
|
or die "/dev/port: $!\n";
|
|
|
|
binmode(IOPORTS);
|
2003-06-28 08:25:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub close_ioports
|
|
|
|
{
|
2008-11-27 18:27:20 +00:00
|
|
|
close(IOPORTS);
|
1999-02-22 18:20:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: port to read
|
|
|
|
# Returns: -1 on failure, read value on success.
|
|
|
|
sub inb
|
|
|
|
{
|
2008-11-27 18:27:20 +00:00
|
|
|
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;
|
1999-02-22 18:20:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: port to write
|
|
|
|
# $_[1]: value to write
|
2008-11-27 18:27:20 +00:00
|
|
|
# We assume this can't fail.
|
1999-02-22 18:20:35 +00:00
|
|
|
sub outb
|
|
|
|
{
|
2008-11-27 18:27:20 +00:00
|
|
|
sysseek(IOPORTS, $_[0], 0);
|
|
|
|
syswrite(IOPORTS, pack("C", $_[1]), 1);
|
1999-02-22 18:20:35 +00:00
|
|
|
}
|
|
|
|
|
1999-02-22 20:40:16 +00:00
|
|
|
# $_[0]: Address register
|
|
|
|
# $_[1]: Data register
|
|
|
|
# $_[2]: Register to read
|
|
|
|
# Returns: read value
|
|
|
|
sub isa_read_byte
|
|
|
|
{
|
2008-11-27 18:27:20 +00:00
|
|
|
outb($_[0], $_[2]);
|
|
|
|
return inb($_[1]);
|
1999-02-22 20:40:16 +00:00
|
|
|
}
|
|
|
|
|
2008-05-28 09:52:16 +00:00
|
|
|
# $_[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
|
|
|
|
{
|
2008-11-27 18:27:20 +00:00
|
|
|
my ($addr, $reg) = @_;
|
|
|
|
return isa_read_byte($addr + 5, $addr + 6, $reg);
|
2008-05-28 09:52:16 +00:00
|
|
|
}
|
|
|
|
|
2003-08-07 09:31:24 +00:00
|
|
|
#################
|
|
|
|
# AUTODETECTION #
|
|
|
|
#################
|
|
|
|
|
2008-11-22 15:52:52 +00:00
|
|
|
use vars qw($dev_i2c $sysfs_root);
|
2003-08-07 09:31:24 +00:00
|
|
|
|
|
|
|
sub initialize_conf
|
|
|
|
{
|
2008-11-28 07:55:10 +00:00
|
|
|
my $use_devfs = 0;
|
|
|
|
open(local *INPUTFILE, "/proc/mounts") or die "Can't access /proc/mounts!";
|
|
|
|
local $_;
|
|
|
|
while (<INPUTFILE>) {
|
|
|
|
if (m@^\w+ /dev devfs @) {
|
|
|
|
$use_devfs = 1;
|
|
|
|
$dev_i2c = '/dev/i2c/';
|
|
|
|
}
|
|
|
|
if (m@^\S+ (/\w+) sysfs @) {
|
|
|
|
$sysfs_root = $1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(INPUTFILE);
|
2004-04-03 14:55:45 +00:00
|
|
|
|
2008-11-28 07:55:10 +00:00
|
|
|
# We need sysfs for many things
|
|
|
|
if (!defined $sysfs_root) {
|
|
|
|
print "Sysfs not mounted?\n";
|
|
|
|
exit -1;
|
|
|
|
}
|
2008-11-22 15:52:52 +00:00
|
|
|
|
2008-11-28 07:55:10 +00:00
|
|
|
my $use_udev = 0;
|
|
|
|
if (open(*INPUTFILE, '/etc/udev/udev.conf')) {
|
|
|
|
while (<INPUTFILE>) {
|
|
|
|
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);
|
|
|
|
}
|
2008-05-22 12:01:33 +00:00
|
|
|
|
2008-11-28 07:55:10 +00:00
|
|
|
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-';
|
|
|
|
}
|
|
|
|
}
|
2004-08-18 19:55:33 +00:00
|
|
|
|
2008-11-28 07:55:10 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2003-08-07 09:31:24 +00:00
|
|
|
}
|
|
|
|
|
2004-03-15 04:23:54 +00:00
|
|
|
# [0] -> VERSION
|
|
|
|
# [1] -> PATCHLEVEL
|
|
|
|
# [2] -> SUBLEVEL
|
|
|
|
# [3] -> EXTRAVERSION
|
|
|
|
#
|
2008-02-20 19:05:00 +00:00
|
|
|
use vars qw(@kernel_version $kernel_arch);
|
2004-03-15 04:23:54 +00:00
|
|
|
|
|
|
|
sub initialize_kernel_version
|
|
|
|
{
|
2008-11-28 07:55:10 +00:00
|
|
|
`uname -r` =~ /(\d+)\.(\d+)\.(\d+)(.*)/;
|
|
|
|
@kernel_version = ($1, $2, $3, $4);
|
|
|
|
chomp($kernel_arch = `uname -m`);
|
2008-11-22 15:52:52 +00:00
|
|
|
|
2008-11-28 07:55:10 +00:00
|
|
|
# We only support kernels >= 2.6.0
|
|
|
|
if (!kernel_version_at_least(2, 6, 0)) {
|
|
|
|
print "Kernel version is unsupported (too old, >= 2.6.0 needed)\n";
|
|
|
|
exit -1;
|
|
|
|
}
|
2004-03-15 04:23:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub kernel_version_at_least
|
|
|
|
{
|
2008-11-28 07:55:10 +00:00
|
|
|
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;
|
2004-03-15 04:23:54 +00:00
|
|
|
}
|
|
|
|
|
2006-10-15 08:46:36 +00:00
|
|
|
# @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
|
|
|
|
{
|
2008-11-28 07:55:10 +00:00
|
|
|
local $_;
|
|
|
|
my $entry;
|
2007-06-25 17:08:15 +00:00
|
|
|
|
2008-11-28 07:55:10 +00:00
|
|
|
open(local *INPUTFILE, "/proc/cpuinfo") or die "Can't access /proc/cpuinfo!";
|
|
|
|
while (<INPUTFILE>) {
|
|
|
|
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
|
2006-10-15 08:46:36 +00:00
|
|
|
}
|
|
|
|
|
2007-06-26 07:47:30 +00:00
|
|
|
# @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: name
|
2008-11-22 15:52:52 +00:00
|
|
|
# (directly taken from /sys/class/i2c-adapter) and driver.
|
2007-06-26 07:47:30 +00:00
|
|
|
use vars qw(@i2c_adapters);
|
|
|
|
|
|
|
|
sub initialize_i2c_adapters_list
|
|
|
|
{
|
2008-11-28 07:55:10 +00:00
|
|
|
my $entry;
|
|
|
|
local $_;
|
2007-06-26 07:47:30 +00:00
|
|
|
|
2008-11-28 07:55:10 +00:00
|
|
|
my $class_dir = "${sysfs_root}/class/i2c-adapter";
|
|
|
|
opendir(local *ADAPTERS, $class_dir) or return;
|
2007-06-26 07:47:30 +00:00
|
|
|
|
2008-11-28 07:55:10 +00:00
|
|
|
while (defined($_ = readdir(ADAPTERS))) {
|
|
|
|
next unless m/^i2c-(\d+)$/;
|
|
|
|
$entry = {}; # New entry
|
|
|
|
$entry->{name} = sysfs_device_attribute("${class_dir}/i2c-$1",
|
|
|
|
"name")
|
|
|
|
|| sysfs_device_attribute("${class_dir}/i2c-$1/device",
|
|
|
|
"name");
|
|
|
|
next if $entry->{name} eq "ISA main adapter";
|
2008-11-24 12:42:00 +00:00
|
|
|
|
2008-11-28 07:55:10 +00:00
|
|
|
# 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("${class_dir}/i2c-$1/device")
|
|
|
|
|| find_i2c_adapter_driver($entry->{name})
|
|
|
|
|| 'UNKNOWN';
|
|
|
|
$i2c_adapters[$1] = $entry;
|
|
|
|
}
|
|
|
|
closedir(ADAPTERS);
|
2007-06-26 07:47:30 +00:00
|
|
|
}
|
|
|
|
|
1999-02-19 01:52:29 +00:00
|
|
|
###########
|
|
|
|
# MODULES #
|
|
|
|
###########
|
|
|
|
|
2008-11-26 14:52:07 +00:00
|
|
|
use vars qw(%modules_list %modules_supported @modules_we_loaded);
|
1999-02-19 01:52:29 +00:00
|
|
|
|
|
|
|
sub initialize_modules_list
|
|
|
|
{
|
2008-11-26 17:17:29 +00:00
|
|
|
local $_;
|
|
|
|
|
|
|
|
open(local *INPUTFILE, "/proc/modules") or return;
|
|
|
|
while (<INPUTFILE>) {
|
|
|
|
tr/-/_/; # Probably not needed
|
|
|
|
$modules_list{$1} = 1 if m/^(\S*)/;
|
|
|
|
}
|
1999-02-19 01:52:29 +00:00
|
|
|
}
|
|
|
|
|
2008-11-26 16:36:04 +00:00
|
|
|
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;
|
|
|
|
}
|
2008-11-27 18:11:11 +00:00
|
|
|
|
2008-11-26 16:36:04 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-07-29 15:58:26 +00:00
|
|
|
sub initialize_modules_supported
|
|
|
|
{
|
2008-11-26 17:17:29 +00:00
|
|
|
foreach my $chip (@chip_ids) {
|
2008-11-30 08:00:51 +00:00
|
|
|
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}++;
|
2008-11-26 17:17:29 +00:00
|
|
|
}
|
2006-07-29 15:58:26 +00:00
|
|
|
}
|
|
|
|
|
2008-11-26 14:52:07 +00:00
|
|
|
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";
|
|
|
|
}
|
|
|
|
|
2006-07-29 15:58:26 +00:00
|
|
|
#################
|
|
|
|
# SYSFS HELPERS #
|
|
|
|
#################
|
|
|
|
|
2008-11-23 15:16:45 +00:00
|
|
|
# From a sysfs device path, return the driver (module) name, or undef
|
2008-11-27 18:10:24 +00:00
|
|
|
sub sysfs_device_driver
|
2006-07-29 15:58:26 +00:00
|
|
|
{
|
2008-11-27 18:10:24 +00:00
|
|
|
my $device = shift;
|
2008-05-22 12:01:33 +00:00
|
|
|
|
2008-11-27 18:10:24 +00:00
|
|
|
my $link = readlink("$device/driver/module");
|
|
|
|
return unless defined $link;
|
|
|
|
return basename($link);
|
2006-07-29 15:58:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# From a sysfs device path and an attribute name, return the attribute
|
|
|
|
# value, or undef
|
2008-11-27 18:10:24 +00:00
|
|
|
sub sysfs_device_attribute
|
2006-07-29 15:58:26 +00:00
|
|
|
{
|
2008-11-27 18:10:24 +00:00
|
|
|
my ($device, $attr) = @_;
|
|
|
|
my $value;
|
2006-07-29 15:58:26 +00:00
|
|
|
|
2008-11-27 18:10:24 +00:00
|
|
|
open(local *FILE, "$device/$attr") or return;
|
|
|
|
$value = <FILE>;
|
|
|
|
close(FILE);
|
|
|
|
return unless defined $value;
|
2006-07-29 15:58:26 +00:00
|
|
|
|
2008-11-27 18:10:24 +00:00
|
|
|
chomp($value);
|
|
|
|
return $value;
|
2006-07-29 15:58:26 +00:00
|
|
|
}
|
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
##############
|
|
|
|
# PCI ACCESS #
|
|
|
|
##############
|
|
|
|
|
2004-03-15 04:23:54 +00:00
|
|
|
use vars qw(%pci_list);
|
1999-02-18 00:19:19 +00:00
|
|
|
|
2006-09-05 10:01:15 +00:00
|
|
|
# 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.
|
2008-11-27 18:16:54 +00:00
|
|
|
sub read_sys_dev_pci
|
2006-09-05 10:01:15 +00:00
|
|
|
{
|
2008-11-27 18:16:54 +00:00
|
|
|
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;
|
|
|
|
}
|
2006-09-05 10:01:15 +00:00
|
|
|
|
2008-11-27 18:16:54 +00:00
|
|
|
return \@pci_list;
|
2006-09-05 10:01:15 +00:00
|
|
|
}
|
|
|
|
|
2008-11-22 15:52:52 +00:00
|
|
|
sub initialize_pci
|
1999-02-06 01:04:57 +00:00
|
|
|
{
|
2008-11-27 18:16:54 +00:00
|
|
|
my $pci_list;
|
|
|
|
local $_;
|
2006-09-05 10:01:15 +00:00
|
|
|
|
2008-11-27 18:16:54 +00:00
|
|
|
$pci_list = read_sys_dev_pci("$sysfs_root/bus/pci/devices");
|
2006-09-05 10:01:15 +00:00
|
|
|
|
2008-11-27 18:16:54 +00:00
|
|
|
# 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};
|
1999-02-17 20:55:23 +00:00
|
|
|
}
|
1999-02-06 01:04:57 +00:00
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
#####################
|
|
|
|
# ADAPTER DETECTION #
|
|
|
|
#####################
|
1999-02-19 01:52:29 +00:00
|
|
|
|
2008-11-30 12:42:41 +00:00
|
|
|
# Not sure if we still need this for Linux 2.6?
|
2004-03-15 04:23:54 +00:00
|
|
|
sub adapter_pci_detection_sis_96x
|
|
|
|
{
|
2008-11-30 12:42:41 +00:00
|
|
|
# Add the appropriate entries to @pci_adapters
|
2008-11-30 12:34:48 +00:00
|
|
|
if (exists $pci_list{'1039:0016'}) {
|
2008-11-30 12:42:41 +00:00
|
|
|
push @pci_adapters, @pci_adapters_sis96x;
|
2008-11-30 12:34:48 +00:00
|
|
|
} elsif (exists $pci_list{'1039:0008'}) {
|
|
|
|
push @pci_adapters, @pci_adapters_sis5595;
|
|
|
|
}
|
2004-03-15 04:23:54 +00:00
|
|
|
}
|
|
|
|
|
2006-09-05 11:35:51 +00:00
|
|
|
# Build and return a PCI device's bus ID
|
2008-11-27 21:41:28 +00:00
|
|
|
sub pci_busid
|
2006-09-05 11:35:51 +00:00
|
|
|
{
|
2008-11-30 12:34:48 +00:00
|
|
|
my $device = shift;
|
|
|
|
my $busid;
|
2006-09-05 11:35:51 +00:00
|
|
|
|
2008-11-30 12:34:48 +00:00
|
|
|
$busid = sprintf("\%02x:\%02x.\%x",
|
|
|
|
$device->{bus}, $device->{slot}, $device->{func});
|
|
|
|
$busid = sprintf("\%04x:", $device->{domain}) . $busid
|
|
|
|
if defined $device->{domain};
|
2006-09-05 11:35:51 +00:00
|
|
|
|
2008-11-30 12:34:48 +00:00
|
|
|
return $busid;
|
2006-09-05 11:35:51 +00:00
|
|
|
}
|
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
sub adapter_pci_detection
|
|
|
|
{
|
2008-11-30 12:34:48 +00:00
|
|
|
my ($key, $device, $try, %smbus, $count);
|
|
|
|
print "Probing for PCI bus adapters...\n";
|
|
|
|
|
|
|
|
# Custom detection routine for some SiS chipsets
|
|
|
|
adapter_pci_detection_sis_96x();
|
|
|
|
|
|
|
|
# Build a list of detected SMBus devices
|
|
|
|
foreach $key (keys %pci_list) {
|
|
|
|
$device = $pci_list{$key};
|
|
|
|
$smbus{$key}++
|
|
|
|
if exists $device->{class} &&
|
|
|
|
$device->{class} == 0x0c05; # SMBus
|
|
|
|
}
|
|
|
|
|
|
|
|
# Loop over the known I2C/SMBus adapters
|
|
|
|
foreach $try (@pci_adapters) {
|
|
|
|
$key = sprintf("%04x:%04x", $try->{vendid}, $try->{devid});
|
2008-11-30 12:53:18 +00:00
|
|
|
next unless exists $pci_list{$key};
|
2008-11-30 12:34:48 +00:00
|
|
|
|
2008-11-30 12:53:18 +00:00
|
|
|
$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... ";
|
|
|
|
<STDIN>;
|
|
|
|
print "\n";
|
2008-11-30 12:34:48 +00:00
|
|
|
}
|
2008-11-30 12:53:18 +00:00
|
|
|
|
|
|
|
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};
|
2008-11-30 12:34:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# 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;
|
1999-02-06 01:04:57 +00:00
|
|
|
}
|
|
|
|
|
2008-11-22 15:52:52 +00:00
|
|
|
# $_[0]: Adapter description as found in /sys/class/i2c-adapter
|
2008-11-24 13:24:00 +00:00
|
|
|
sub find_i2c_adapter_driver
|
1999-02-19 18:11:03 +00:00
|
|
|
{
|
2008-11-24 13:24:00 +00:00
|
|
|
my $name = shift;
|
|
|
|
my $entry;
|
|
|
|
|
|
|
|
foreach $entry (@i2c_adapter_names) {
|
|
|
|
return $entry->{driver}
|
|
|
|
if $name =~ $entry->{match};
|
|
|
|
}
|
1999-02-19 18:11:03 +00:00
|
|
|
}
|
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
#############################
|
|
|
|
# I2C AND SMBUS /DEV ACCESS #
|
|
|
|
#############################
|
|
|
|
|
1999-02-18 00:19:19 +00:00
|
|
|
# This should really go into a separate module/package.
|
|
|
|
|
2006-04-22 09:06:21 +00:00
|
|
|
# These are copied from <linux/i2c-dev.h>
|
1999-02-17 20:55:23 +00:00
|
|
|
|
2008-11-30 13:05:38 +00:00
|
|
|
use constant IOCTL_I2C_SLAVE => 0x0703;
|
|
|
|
use constant IOCTL_I2C_FUNCS => 0x0705;
|
|
|
|
use constant IOCTL_I2C_SMBUS => 0x0720;
|
1999-02-17 23:24:24 +00:00
|
|
|
|
2008-11-30 13:05:38 +00:00
|
|
|
use constant SMBUS_READ => 1;
|
|
|
|
use constant SMBUS_WRITE => 0;
|
2004-07-14 14:58:21 +00:00
|
|
|
|
2008-11-30 13:05:38 +00:00
|
|
|
use constant SMBUS_QUICK => 0;
|
|
|
|
use constant SMBUS_BYTE => 1;
|
|
|
|
use constant SMBUS_BYTE_DATA => 2;
|
|
|
|
use constant SMBUS_WORD_DATA => 3;
|
1999-02-17 20:55:23 +00:00
|
|
|
|
2006-08-09 06:45:48 +00:00
|
|
|
use constant I2C_FUNC_SMBUS_QUICK => 0x00010000;
|
|
|
|
use constant I2C_FUNC_SMBUS_READ_BYTE => 0x00020000;
|
|
|
|
|
|
|
|
# Get the i2c adapter's functionalities
|
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# Returns: -1 on failure, functionality bitfield on success.
|
2008-11-27 21:41:28 +00:00
|
|
|
sub i2c_get_funcs
|
2006-08-09 06:45:48 +00:00
|
|
|
{
|
2008-11-30 13:05:38 +00:00
|
|
|
my $file = shift;
|
|
|
|
my $funcs = pack("L", 0); # Allocate space
|
2006-08-09 06:45:48 +00:00
|
|
|
|
2008-11-30 13:05:38 +00:00
|
|
|
ioctl($file, IOCTL_I2C_FUNCS, $funcs) or return -1;
|
|
|
|
$funcs = unpack("L", $funcs);
|
2006-08-09 06:45:48 +00:00
|
|
|
|
2008-11-30 13:05:38 +00:00
|
|
|
return $funcs;
|
2006-08-09 06:45:48 +00:00
|
|
|
}
|
|
|
|
|
1999-02-17 23:24:24 +00:00
|
|
|
# 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.
|
1999-02-17 20:55:23 +00:00
|
|
|
sub i2c_set_slave_addr
|
|
|
|
{
|
2008-11-30 13:05:38 +00:00
|
|
|
my ($file, $addr) = @_;
|
2008-05-28 07:26:11 +00:00
|
|
|
|
2008-11-30 13:05:38 +00:00
|
|
|
# Reset register data cache
|
|
|
|
@i2c_byte_cache = ();
|
2008-05-28 07:26:11 +00:00
|
|
|
|
2008-11-30 13:05:38 +00:00
|
|
|
$addr += 0; # Make sure it's a number not a string
|
|
|
|
ioctl($file, IOCTL_I2C_SLAVE, $addr) or return 0;
|
|
|
|
return 1;
|
1999-02-17 20:55:23 +00:00
|
|
|
}
|
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
# i2c_smbus_access is based upon the corresponding C function (see
|
1999-02-17 23:24:24 +00:00
|
|
|
# <linux/i2c-dev.h>). You should not need to call this directly.
|
|
|
|
# $_[0]: Reference to an opened filehandle
|
2004-07-14 14:58:21 +00:00
|
|
|
# $_[1]: SMBUS_READ for reading, SMBUS_WRITE for writing
|
1999-02-17 23:24:24 +00:00
|
|
|
# $_[2]: Command (usually register number)
|
2004-07-14 14:58:21 +00:00
|
|
|
# $_[3]: Transaction kind (SMBUS_BYTE, SMBUS_BYTE_DATA, etc.)
|
1999-02-17 23:24:24 +00:00
|
|
|
# $_[4]: Reference to an array used for input/output of data
|
|
|
|
# Returns: 0 on failure, 1 on success.
|
1999-02-18 00:19:19 +00:00
|
|
|
# Note that we need to get back to Integer boundaries through the 'x2'
|
2008-05-22 12:01:33 +00:00
|
|
|
# in the pack. This is very compiler-dependent; I wish there was some other
|
1999-02-18 00:19:19 +00:00
|
|
|
# way to do this.
|
1999-02-17 20:55:23 +00:00
|
|
|
sub i2c_smbus_access
|
|
|
|
{
|
2008-11-30 13:05:38 +00:00
|
|
|
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;
|
1999-02-17 20:55:23 +00:00
|
|
|
}
|
|
|
|
|
1999-02-17 23:24:24 +00:00
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# Returns: -1 on failure, the read byte on success.
|
|
|
|
sub i2c_smbus_read_byte
|
|
|
|
{
|
2008-11-30 13:05:38 +00:00
|
|
|
my ($file) = @_;
|
|
|
|
my @data;
|
|
|
|
|
|
|
|
i2c_smbus_access($file, SMBUS_READ, 0, SMBUS_BYTE, \@data)
|
|
|
|
or return -1;
|
|
|
|
return $data[0];
|
1999-02-17 23:24:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# $_[1]: Command byte (usually register number)
|
|
|
|
# Returns: -1 on failure, the read byte on success.
|
2008-05-28 07:26:11 +00:00
|
|
|
# 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.
|
1999-02-17 23:24:24 +00:00
|
|
|
sub i2c_smbus_read_byte_data
|
|
|
|
{
|
2008-11-30 13:05:38 +00:00
|
|
|
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]);
|
1999-02-17 20:55:23 +00:00
|
|
|
}
|
2008-05-22 12:01:33 +00:00
|
|
|
|
1999-02-17 23:24:24 +00:00
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# $_[1]: Command byte (usually register number)
|
1999-02-18 00:19:19 +00:00
|
|
|
# Returns: -1 on failure, the read word on success.
|
2008-05-11 17:12:29 +00:00
|
|
|
# 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.
|
2008-11-30 10:29:22 +00:00
|
|
|
# Note: some devices use the wrong endianness.
|
1999-02-18 00:19:19 +00:00
|
|
|
sub i2c_smbus_read_word_data
|
1999-02-17 23:24:24 +00:00
|
|
|
{
|
2008-11-30 13:05:38 +00:00
|
|
|
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];
|
1999-02-17 23:24:24 +00:00
|
|
|
}
|
|
|
|
|
2004-04-20 19:40:02 +00:00
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# $_[1]: Address
|
2006-08-09 06:45:48 +00:00
|
|
|
# $_[2]: Functionalities of this i2c adapter
|
2004-04-20 19:40:02 +00:00
|
|
|
# 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.
|
2008-11-27 21:41:28 +00:00
|
|
|
sub i2c_probe
|
2004-04-20 19:40:02 +00:00
|
|
|
{
|
2008-11-30 13:05:38 +00:00
|
|
|
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);
|
2008-11-30 13:10:09 +00:00
|
|
|
return i2c_smbus_access($file, SMBUS_READ, 0, SMBUS_BYTE, []);
|
2008-11-30 13:05:38 +00:00
|
|
|
} else {
|
|
|
|
return 0 unless ($funcs & I2C_FUNC_SMBUS_QUICK);
|
2008-11-30 13:10:09 +00:00
|
|
|
return i2c_smbus_access($file, SMBUS_WRITE, 0, SMBUS_QUICK, []);
|
2008-11-30 13:05:38 +00:00
|
|
|
}
|
2004-04-20 19:40:02 +00:00
|
|
|
}
|
|
|
|
|
2008-05-11 17:04:03 +00:00
|
|
|
# $_[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
|
|
|
|
{
|
2008-11-30 13:05:38 +00:00
|
|
|
my ($file) = @_;
|
|
|
|
my $data;
|
2008-05-11 17:04:03 +00:00
|
|
|
|
2008-11-30 13:05:38 +00:00
|
|
|
# First we receive a byte from the chip, and remember it.
|
|
|
|
$data = i2c_smbus_read_byte($file);
|
|
|
|
return 1 if ($data < 0);
|
2008-05-11 17:04:03 +00:00
|
|
|
|
2008-11-30 13:05:38 +00:00
|
|
|
# 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);
|
2008-05-11 17:04:03 +00:00
|
|
|
|
2008-11-30 13:05:38 +00:00
|
|
|
# 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);
|
2008-05-11 17:04:03 +00:00
|
|
|
|
2008-11-30 13:05:38 +00:00
|
|
|
# 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));
|
2008-05-11 17:04:03 +00:00
|
|
|
|
2008-11-30 13:05:38 +00:00
|
|
|
# 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;
|
2008-05-11 17:04:03 +00:00
|
|
|
}
|
|
|
|
|
1999-02-18 00:19:19 +00:00
|
|
|
####################
|
|
|
|
# ADAPTER SCANNING #
|
|
|
|
####################
|
1999-02-17 23:24:24 +00:00
|
|
|
|
1999-02-19 18:11:03 +00:00
|
|
|
use vars qw(@chips_detected);
|
|
|
|
|
|
|
|
# We will build a complicated structure @chips_detected here, being:
|
|
|
|
# A list of
|
|
|
|
# references to hashes
|
|
|
|
# with field 'driver', being a string with the driver name for this chip;
|
|
|
|
# with field 'detected'
|
|
|
|
# being a reference to a list of
|
1999-02-28 17:41:46 +00:00
|
|
|
# references to hashes of type 'detect_data';
|
|
|
|
|
|
|
|
# Type detect_data:
|
|
|
|
# A hash
|
|
|
|
# with field 'i2c_adap' containing an adapter string as appearing
|
2008-11-22 15:52:52 +00:00
|
|
|
# in /sys/class/i2c-adapter (if this is an I2C detection)
|
1999-02-28 17:41:46 +00:00
|
|
|
# with field 'i2c_devnr', contianing the /dev/i2c-* number of this
|
|
|
|
# adapter (if this is an I2C detection)
|
|
|
|
# with field 'i2c_driver', containing the driver name for 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)
|
2008-05-22 12:01:33 +00:00
|
|
|
# with field 'isa_addr' containing the ISA address this chip is on
|
1999-02-28 17:41:46 +00:00
|
|
|
# (if this is an ISA detection)
|
|
|
|
# with field 'conf', containing the confidence level of this detection
|
|
|
|
# with field 'chipname', containing the chip name
|
|
|
|
|
|
|
|
# This adds a detection to the above structure. We do no alias detection
|
|
|
|
# here; so you should do ISA detections *after* all I2C detections.
|
|
|
|
# Not all possibilities of i2c_addr and i2c_sub_addrs are exhausted.
|
|
|
|
# In all normal cases, it should be all right.
|
1999-02-19 18:11:03 +00:00
|
|
|
# $_[0]: chip driver
|
|
|
|
# $_[1]: reference to data hash
|
1999-02-28 17:41:46 +00:00
|
|
|
# Returns: Nothing
|
|
|
|
sub add_i2c_to_chips_detected
|
1999-02-19 18:11:03 +00:00
|
|
|
{
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($chipdriver, $datahash) = @_;
|
2008-11-27 16:00:04 +00:00
|
|
|
my ($i, $new_detected_ref, $detected_ref,
|
|
|
|
$main_entry, $detected_entry, $put_in_detected, @hash_addrs, @entry_addrs);
|
1999-02-28 17:41:46 +00:00
|
|
|
|
|
|
|
# First determine where the hash has to be added.
|
1999-02-19 18:11:03 +00:00
|
|
|
for ($i = 0; $i < @chips_detected; $i++) {
|
|
|
|
last if ($chips_detected[$i]->{driver} eq $chipdriver);
|
|
|
|
}
|
|
|
|
if ($i == @chips_detected) {
|
|
|
|
push @chips_detected, { driver => $chipdriver,
|
2008-11-27 16:00:04 +00:00
|
|
|
detected => [] };
|
1999-02-19 18:11:03 +00:00
|
|
|
}
|
|
|
|
$new_detected_ref = $chips_detected[$i]->{detected};
|
|
|
|
|
2008-11-27 16:00:04 +00:00
|
|
|
# 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.
|
1999-03-02 08:08:29 +00:00
|
|
|
@hash_addrs = ($datahash->{i2c_addr});
|
|
|
|
push @hash_addrs, @{$datahash->{i2c_sub_addrs}}
|
|
|
|
if exists $datahash->{i2c_sub_addrs};
|
1999-02-28 17:41:46 +00:00
|
|
|
$put_in_detected = 1;
|
|
|
|
FIND_LOOP:
|
|
|
|
foreach $main_entry (@chips_detected) {
|
|
|
|
foreach $detected_entry (@{$main_entry->{detected}}) {
|
1999-03-02 10:04:21 +00:00
|
|
|
@entry_addrs = ($detected_entry->{i2c_addr});
|
|
|
|
push @entry_addrs, @{$detected_entry->{i2c_sub_addrs}}
|
1999-03-02 11:13:46 +00:00
|
|
|
if exists $detected_entry->{i2c_sub_addrs};
|
1999-02-28 17:41:46 +00:00
|
|
|
if ($detected_entry->{i2c_devnr} == $datahash->{i2c_devnr} and
|
2008-05-28 09:32:41 +00:00
|
|
|
any_list_match(\@entry_addrs, \@hash_addrs)) {
|
1999-02-28 17:41:46 +00:00
|
|
|
if ($detected_entry->{conf} >= $datahash->{conf}) {
|
|
|
|
$put_in_detected = 0;
|
|
|
|
}
|
|
|
|
last FIND_LOOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($put_in_detected) {
|
2008-11-27 16:00:04 +00:00
|
|
|
# Here, we discard all entries which
|
1999-02-28 17:41:46 +00:00
|
|
|
# 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 $main_entry (@chips_detected) {
|
|
|
|
$detected_ref = $main_entry->{detected};
|
|
|
|
for ($i = @$detected_ref-1; $i >=0; $i--) {
|
|
|
|
@entry_addrs = ($detected_ref->[$i]->{i2c_addr});
|
|
|
|
push @entry_addrs, @{$detected_ref->[$i]->{i2c_sub_addrs}}
|
|
|
|
if exists $detected_ref->[$i]->{i2c_sub_addrs};
|
1999-12-29 20:13:25 +00:00
|
|
|
if ($detected_ref->[$i]->{i2c_devnr} == $datahash->{i2c_devnr} and
|
2008-05-28 09:32:41 +00:00
|
|
|
any_list_match(\@entry_addrs, \@hash_addrs)) {
|
1999-02-28 17:41:46 +00:00
|
|
|
splice @$detected_ref, $i, 1;
|
1999-02-19 18:11:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-02-28 17:41:46 +00:00
|
|
|
|
|
|
|
# Now add the new entry to detected
|
|
|
|
push @$new_detected_ref, $datahash;
|
1999-02-19 18:11:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-02-28 17:41:46 +00:00
|
|
|
# This adds a detection to the above structure. We also do alias detection
|
|
|
|
# here; so you should do ISA detections *after* all I2C detections.
|
|
|
|
# $_[0]: alias detection function
|
|
|
|
# $_[1]: chip driver
|
|
|
|
# $_[2]: reference to data hash
|
1999-12-05 20:15:43 +00:00
|
|
|
# Returns: 0 if it is not an alias, datahash reference if it is.
|
1999-02-23 14:14:32 +00:00
|
|
|
sub add_isa_to_chips_detected
|
|
|
|
{
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($alias_detect, $chipdriver, $datahash) = @_;
|
2008-11-27 16:00:04 +00:00
|
|
|
my ($i, $new_detected_ref, $detected_ref, $main_entry, $isalias);
|
1999-02-23 14:14:32 +00:00
|
|
|
|
1999-02-28 17:41:46 +00:00
|
|
|
# First determine where the hash has to be added.
|
2008-05-28 09:32:41 +00:00
|
|
|
$isalias = 0;
|
1999-02-23 14:14:32 +00:00
|
|
|
for ($i = 0; $i < @chips_detected; $i++) {
|
|
|
|
last if ($chips_detected[$i]->{driver} eq $chipdriver);
|
|
|
|
}
|
|
|
|
if ($i == @chips_detected) {
|
|
|
|
push @chips_detected, { driver => $chipdriver,
|
2008-11-27 16:00:04 +00:00
|
|
|
detected => [] };
|
1999-02-23 14:14:32 +00:00
|
|
|
}
|
|
|
|
$new_detected_ref = $chips_detected[$i]->{detected};
|
1999-02-28 17:41:46 +00:00
|
|
|
|
1999-02-23 20:28:05 +00:00
|
|
|
# Now, we are looking for aliases. An alias can only be the same chiptype.
|
2008-11-27 16:00:04 +00:00
|
|
|
# If it is found in the detected list, we
|
1999-02-28 17:41:46 +00:00
|
|
|
# still have to check whether another chip has claimed this ISA address.
|
|
|
|
# So we remove the old entry from the detected list and put it in datahash.
|
|
|
|
for ($i = 0; $i < @$new_detected_ref; $i++) {
|
|
|
|
if (exists $new_detected_ref->[$i]->{i2c_addr} and
|
|
|
|
not exists $new_detected_ref->[$i]->{isa_addr} and
|
|
|
|
defined $alias_detect and
|
|
|
|
$new_detected_ref->[$i]->{chipname} eq $datahash->{chipname}) {
|
2004-07-14 13:52:19 +00:00
|
|
|
open(local *FILE, "$dev_i2c$new_detected_ref->[$i]->{i2c_devnr}") or
|
2003-08-07 09:31:24 +00:00
|
|
|
print("Can't open $dev_i2c$new_detected_ref->[$i]->{i2c_devnr}?!?\n"),
|
|
|
|
next;
|
2008-05-28 09:32:41 +00:00
|
|
|
binmode(FILE);
|
|
|
|
i2c_set_slave_addr(\*FILE, $new_detected_ref->[$i]->{i2c_addr}) or
|
1999-02-25 08:37:29 +00:00
|
|
|
print("Can't set I2C address for ",
|
2003-08-07 09:31:24 +00:00
|
|
|
"$dev_i2c$new_detected_ref->[$i]->{i2c_devnr}?!?\n"),
|
1999-02-25 08:37:29 +00:00
|
|
|
next;
|
2008-05-22 12:01:33 +00:00
|
|
|
if (&$alias_detect ($datahash->{isa_addr}, \*FILE,
|
1999-02-28 17:41:46 +00:00
|
|
|
$new_detected_ref->[$i]->{i2c_addr})) {
|
|
|
|
$new_detected_ref->[$i]->{isa_addr} = $datahash->{isa_addr};
|
|
|
|
($datahash) = splice (@$new_detected_ref, $i, 1);
|
2008-05-28 09:32:41 +00:00
|
|
|
$isalias = 1;
|
1999-02-23 20:28:05 +00:00
|
|
|
last;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-02-28 17:41:46 +00:00
|
|
|
|
2008-11-27 16:00:04 +00:00
|
|
|
# Find out whether our new entry should go into the detected list
|
|
|
|
# or not. We only compare main isa_addr here, of course.
|
1999-02-28 17:41:46 +00:00
|
|
|
foreach $main_entry (@chips_detected) {
|
|
|
|
$detected_ref = $main_entry->{detected};
|
|
|
|
for ($i = 0; $i < @{$main_entry->{detected}}; $i++) {
|
|
|
|
if (exists $detected_ref->[$i]->{isa_addr} and
|
2006-10-15 09:30:45 +00:00
|
|
|
exists $datahash->{isa_addr} and
|
1999-02-28 17:41:46 +00:00
|
|
|
$detected_ref->[$i]->{isa_addr} == $datahash->{isa_addr}) {
|
2008-11-27 16:00:04 +00:00
|
|
|
if ($detected_ref->[$i]->{conf} < $datahash->{conf}) {
|
2008-05-22 12:01:33 +00:00
|
|
|
splice @$detected_ref, $i, 1;
|
1999-02-28 17:41:46 +00:00
|
|
|
push @$new_detected_ref, $datahash;
|
1999-02-23 14:14:32 +00:00
|
|
|
}
|
1999-12-05 20:15:43 +00:00
|
|
|
if ($isalias) {
|
|
|
|
return $datahash;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
1999-02-23 14:14:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-02-28 17:41:46 +00:00
|
|
|
|
1999-03-02 08:08:29 +00:00
|
|
|
# Not found? OK, put it in the detected list
|
1999-02-28 17:41:46 +00:00
|
|
|
push @$new_detected_ref, $datahash;
|
1999-12-05 20:15:43 +00:00
|
|
|
if ($isalias) {
|
|
|
|
return $datahash;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
1999-02-23 14:14:32 +00:00
|
|
|
}
|
|
|
|
|
2007-04-03 12:55:30 +00:00
|
|
|
# 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.
|
2008-11-27 21:41:28 +00:00
|
|
|
sub i2c_addresses_to_scan
|
2007-04-03 12:55:30 +00:00
|
|
|
{
|
|
|
|
my @used;
|
|
|
|
my @addresses;
|
|
|
|
my $addr;
|
|
|
|
|
|
|
|
foreach my $chip (@chip_ids) {
|
2008-11-27 21:46:01 +00:00
|
|
|
next unless defined $chip->{i2c_addrs};
|
|
|
|
foreach $addr (@{$chip->{i2c_addrs}}) {
|
2007-04-03 12:55:30 +00:00
|
|
|
$used[$addr]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for ($addr = 0x03; $addr <= 0x77; $addr++) {
|
|
|
|
push @addresses, $addr if $used[$addr];
|
|
|
|
}
|
|
|
|
return \@addresses;
|
|
|
|
}
|
|
|
|
|
1999-02-18 00:19:19 +00:00
|
|
|
# $_[0]: The number of the adapter to scan
|
2008-11-22 15:52:52 +00:00
|
|
|
# $_[1]: The name of the adapter, as appearing in /sys/class/i2c-adapter
|
2005-09-10 14:39:55 +00:00
|
|
|
# $_[2]: The driver of the adapter
|
|
|
|
# @_[3]: Addresses not to scan (array reference)
|
1999-02-18 00:19:19 +00:00
|
|
|
sub scan_adapter
|
1999-02-17 23:24:24 +00:00
|
|
|
{
|
2005-09-10 14:39:55 +00:00
|
|
|
my ($adapter_nr, $adapter_name, $adapter_driver, $not_to_scan) = @_;
|
2006-08-09 06:45:48 +00:00
|
|
|
my ($funcs, $chip, $addr, $conf, @chips, $new_hash, $other_addr);
|
1999-02-28 17:41:46 +00:00
|
|
|
|
|
|
|
# As we modify it, we need a copy
|
1999-02-24 00:22:52 +00:00
|
|
|
my @not_to_scan = @$not_to_scan;
|
1999-02-28 17:41:46 +00:00
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
open(local *FILE, "$dev_i2c$adapter_nr") or
|
2003-08-07 09:31:24 +00:00
|
|
|
(print "Can't open $dev_i2c$adapter_nr\n"), return;
|
2008-05-28 09:32:41 +00:00
|
|
|
binmode(FILE);
|
1999-02-28 17:41:46 +00:00
|
|
|
|
2006-08-09 06:45:48 +00:00
|
|
|
# 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))) {
|
|
|
|
print "Adapter cannot be probed, skipping.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (~$funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE)) {
|
|
|
|
print "Adapter doesn't support all probing functions.\n",
|
|
|
|
"Some addresses won't be probed.\n";
|
|
|
|
}
|
|
|
|
|
1999-02-28 17:41:46 +00:00
|
|
|
# Now scan each address in turn
|
2007-04-03 12:55:30 +00:00
|
|
|
foreach $addr (@{$i2c_addresses_to_scan}) {
|
1999-02-28 17:41:46 +00:00
|
|
|
# As the not_to_scan list is sorted, we can check it fast
|
2008-05-09 17:59:51 +00:00
|
|
|
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);
|
1999-02-24 00:22:52 +00:00
|
|
|
if (@not_to_scan and $not_to_scan[0] == $addr) {
|
|
|
|
shift @not_to_scan;
|
|
|
|
next;
|
|
|
|
}
|
1999-02-28 17:41:46 +00:00
|
|
|
|
2006-07-29 15:58:26 +00:00
|
|
|
if (!i2c_set_slave_addr(\*FILE, $addr)) {
|
2008-11-22 15:52:52 +00:00
|
|
|
# If the address is busy, we can normally find out which driver
|
2008-11-23 15:16:45 +00:00
|
|
|
# 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.
|
2006-07-29 15:58:26 +00:00
|
|
|
my ($device, $driver);
|
2008-11-22 15:52:52 +00:00
|
|
|
|
|
|
|
$device = sprintf("$sysfs_root/bus/i2c/devices/\%d-\%04x",
|
2006-07-29 15:58:26 +00:00
|
|
|
$adapter_nr, $addr);
|
2008-11-22 15:52:52 +00:00
|
|
|
$driver = sysfs_device_driver($device);
|
|
|
|
|
2006-07-29 15:58:26 +00:00
|
|
|
if (defined($driver)) {
|
|
|
|
$new_hash = {
|
|
|
|
conf => 6, # Arbitrary confidence
|
|
|
|
i2c_addr => $addr,
|
|
|
|
chipname => sysfs_device_attribute($device, "name") || "unknown",
|
|
|
|
i2c_adap => $adapter_name,
|
|
|
|
i2c_driver => $adapter_driver,
|
|
|
|
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 {
|
2006-08-25 19:59:29 +00:00
|
|
|
print " (note: this is probably NOT a sensor chip!)\n";
|
2008-05-22 12:01:33 +00:00
|
|
|
}
|
2006-07-29 15:58:26 +00:00
|
|
|
} else {
|
|
|
|
printf("Client at address 0x%02x can not be probed - ".
|
|
|
|
"unload all client drivers first!\n", $addr);
|
|
|
|
}
|
|
|
|
next;
|
|
|
|
}
|
1999-02-28 17:41:46 +00:00
|
|
|
|
2006-08-09 06:45:48 +00:00
|
|
|
next unless i2c_probe(\*FILE, $addr, $funcs);
|
2008-05-22 12:01:33 +00:00
|
|
|
printf "Client found at address 0x%02x\n", $addr;
|
2008-05-11 17:04:03 +00:00
|
|
|
if (!i2c_safety_check(\*FILE)) {
|
|
|
|
print "Seems to be a 1-register-only device, skipping.\n";
|
|
|
|
next;
|
|
|
|
}
|
1999-02-28 17:41:46 +00:00
|
|
|
|
2007-04-03 12:55:30 +00:00
|
|
|
$| = 1;
|
2008-11-30 09:09:04 +00:00
|
|
|
foreach $chip (@chip_ids, @non_hwmon_chip_ids) {
|
2008-05-28 09:32:41 +00:00
|
|
|
if (exists $chip->{i2c_addrs} and contains($addr, @{$chip->{i2c_addrs}})) {
|
2006-09-01 16:45:50 +00:00
|
|
|
printf("\%-60s", sprintf("Probing for `\%s'... ", $chip->{name}));
|
2008-05-22 12:01:33 +00:00
|
|
|
if (($conf, @chips) = &{$chip->{i2c_detect}} (\*FILE, $addr)) {
|
2007-07-14 16:29:52 +00:00
|
|
|
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}'";
|
|
|
|
}
|
1999-02-19 01:52:29 +00:00
|
|
|
if (@chips) {
|
1999-02-25 08:30:04 +00:00
|
|
|
print ", other addresses:";
|
1999-02-28 17:41:46 +00:00
|
|
|
@chips = sort @chips;
|
2007-07-14 16:32:56 +00:00
|
|
|
foreach $other_addr (@chips) {
|
2008-05-22 12:01:33 +00:00
|
|
|
printf(" 0x%02x", $other_addr);
|
1999-02-25 08:30:04 +00:00
|
|
|
}
|
1999-02-20 00:54:55 +00:00
|
|
|
}
|
2007-07-14 16:29:52 +00:00
|
|
|
printf ")\n";
|
|
|
|
|
|
|
|
next if ($chip->{driver} eq "not-a-sensor"
|
|
|
|
|| $chip->{driver} eq "use-isa-instead");
|
|
|
|
|
1999-02-28 17:41:46 +00:00
|
|
|
$new_hash = { conf => $conf,
|
|
|
|
i2c_addr => $addr,
|
2004-07-14 14:58:21 +00:00
|
|
|
chipname => $chip->{name},
|
1999-02-28 17:41:46 +00:00
|
|
|
i2c_adap => $adapter_name,
|
|
|
|
i2c_driver => $adapter_driver,
|
|
|
|
i2c_devnr => $adapter_nr,
|
|
|
|
};
|
1999-03-01 13:49:06 +00:00
|
|
|
if (@chips) {
|
|
|
|
my @chips_copy = @chips;
|
|
|
|
$new_hash->{i2c_sub_addrs} = \@chips_copy;
|
|
|
|
}
|
2008-05-28 09:32:41 +00:00
|
|
|
add_i2c_to_chips_detected($chip->{driver}, $new_hash);
|
1999-02-18 18:09:14 +00:00
|
|
|
} else {
|
2006-09-01 16:45:50 +00:00
|
|
|
print "No\n";
|
1999-02-18 18:09:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-04-03 12:55:30 +00:00
|
|
|
$| = 0;
|
1999-02-18 00:19:19 +00:00
|
|
|
}
|
1999-02-17 23:24:24 +00:00
|
|
|
}
|
|
|
|
|
1999-02-23 14:14:32 +00:00
|
|
|
sub scan_isa_bus
|
|
|
|
{
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($chip, $addr, $conf);
|
2007-04-03 12:55:30 +00:00
|
|
|
$| = 1;
|
1999-02-23 14:14:32 +00:00
|
|
|
foreach $chip (@chip_ids) {
|
2004-07-14 14:58:21 +00:00
|
|
|
next if not exists $chip->{isa_addrs} or not exists $chip->{isa_detect};
|
|
|
|
foreach $addr (@{$chip->{isa_addrs}}) {
|
2008-02-20 19:31:34 +00:00
|
|
|
printf("\%-60s", sprintf("Probing for `\%s'\ at 0x\%x... ", $chip->{name},
|
|
|
|
$addr));
|
2004-07-14 14:58:21 +00:00
|
|
|
$conf = &{$chip->{isa_detect}} ($addr);
|
2006-09-01 16:45:50 +00:00
|
|
|
print("No\n"), next if not defined $conf;
|
1999-02-23 14:14:32 +00:00
|
|
|
print "Success!\n";
|
2004-07-14 14:58:21 +00:00
|
|
|
printf " (confidence %d, driver `%s')\n", $conf, $chip->{driver};
|
1999-03-23 21:48:41 +00:00
|
|
|
my $new_hash = { conf => $conf,
|
|
|
|
isa_addr => $addr,
|
2004-07-14 14:58:21 +00:00
|
|
|
chipname => $chip->{name}
|
1999-03-23 21:48:41 +00:00
|
|
|
};
|
2008-05-28 09:32:41 +00:00
|
|
|
$new_hash = add_isa_to_chips_detected($chip->{alias_detect}, $chip->{driver},
|
|
|
|
$new_hash);
|
1999-12-05 20:15:43 +00:00
|
|
|
if ($new_hash) {
|
2008-11-27 15:00:21 +00:00
|
|
|
printf " Alias of the chip on I2C bus `%s', address 0x%02x\n",
|
2008-05-22 12:01:33 +00:00
|
|
|
$new_hash->{i2c_adap}, $new_hash->{i2c_addr};
|
1999-12-05 20:15:43 +00:00
|
|
|
}
|
1999-02-23 14:14:32 +00:00
|
|
|
}
|
|
|
|
}
|
2007-04-03 12:55:30 +00:00
|
|
|
$| = 0;
|
1999-02-23 14:14:32 +00:00
|
|
|
}
|
|
|
|
|
2006-09-01 19:22:13 +00:00
|
|
|
use vars qw(%superio);
|
|
|
|
|
2006-10-15 08:48:36 +00:00
|
|
|
# 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
|
2006-09-01 19:22:13 +00:00
|
|
|
%superio = (
|
2008-11-30 14:31:03 +00:00
|
|
|
devidreg => 0x20,
|
|
|
|
logdevreg => 0x07,
|
|
|
|
actreg => 0x30,
|
|
|
|
actmask => 0x01,
|
|
|
|
basereg => 0x60,
|
2006-09-01 19:22:13 +00:00
|
|
|
);
|
|
|
|
|
2004-02-28 22:00:35 +00:00
|
|
|
sub exit_superio
|
|
|
|
{
|
2008-11-30 14:31:03 +00:00
|
|
|
my ($addrreg, $datareg) = @_;
|
2004-03-03 20:19:10 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
# Some chips (SMSC, Winbond) want this
|
|
|
|
outb($addrreg, 0xaa);
|
2004-03-02 21:05:44 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
# Return to "Wait For Key" state (PNP-ISA spec)
|
|
|
|
outb($addrreg, 0x02);
|
|
|
|
outb($datareg, 0x02);
|
2004-02-28 22:00:35 +00:00
|
|
|
}
|
|
|
|
|
2006-09-05 12:09:30 +00:00
|
|
|
# Guess if an unknown Super-I/O chip has sensors
|
2008-11-27 21:41:28 +00:00
|
|
|
sub guess_superio_ld
|
2006-09-05 12:09:30 +00:00
|
|
|
{
|
2008-11-30 14:31:03 +00:00
|
|
|
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;
|
|
|
|
}
|
2006-09-05 12:09:30 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
# Be nice, restore original logical device
|
|
|
|
outb($addrreg, $superio{logdevreg});
|
|
|
|
outb($datareg, $oldldn);
|
2006-09-05 12:09:30 +00:00
|
|
|
}
|
|
|
|
|
2008-11-27 21:41:28 +00:00
|
|
|
sub probe_superio
|
2006-09-01 19:22:13 +00:00
|
|
|
{
|
2008-11-30 14:31:03 +00:00
|
|
|
my ($addrreg, $datareg, $chip) = @_;
|
|
|
|
my ($val, $addr);
|
2006-09-01 19:22:13 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
printf "\%-60s", "Found `$chip->{name}'";
|
2006-09-01 19:22:13 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
# Does it have hardware monitoring capabilities?
|
|
|
|
if (!exists $chip->{driver}) {
|
|
|
|
print "\n (no information available)\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ($chip->{driver} eq "not-a-sensor") {
|
|
|
|
print "\n (no hardware monitoring capabilities)\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ($chip->{driver} eq "via-smbus-only") {
|
|
|
|
print "\n (hardware monitoring capabilities accessible via SMBus only)\n";
|
|
|
|
return;
|
|
|
|
}
|
2006-09-01 19:22:13 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
# Switch to the sensor logical device
|
|
|
|
outb($addrreg, $superio{logdevreg});
|
|
|
|
outb($datareg, $chip->{logdev});
|
2006-09-01 19:22:13 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
# Check the activation register
|
|
|
|
outb($addrreg, $superio{actreg});
|
|
|
|
$val = inb($datareg);
|
|
|
|
if (!($val & $superio{actmask})) {
|
|
|
|
print "\n (but not activated)\n";
|
|
|
|
return;
|
|
|
|
}
|
2006-09-01 19:22:13 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
# Get the IO base register
|
|
|
|
outb($addrreg, $superio{basereg});
|
|
|
|
$addr = inb($datareg);
|
|
|
|
outb($addrreg, $superio{basereg} + 1);
|
|
|
|
$addr = ($addr << 8) | inb($datareg);
|
|
|
|
if ($addr == 0) {
|
|
|
|
print "\n (but no address specified)\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
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->{alias_detect}, $chip->{driver},
|
|
|
|
$new_hash);
|
2006-09-01 19:22:13 +00:00
|
|
|
}
|
|
|
|
|
2007-06-25 19:02:25 +00:00
|
|
|
# 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
|
|
|
|
{
|
2008-11-30 14:31:03 +00:00
|
|
|
my ($addrreg, $datareg, $ns_chips) = @_;
|
|
|
|
my ($val, $chip);
|
2007-06-25 19:02:25 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
# read alternate device ID register
|
|
|
|
outb($addrreg, 0x0d);
|
|
|
|
$val = inb($datareg);
|
|
|
|
return 0 if $val == 0x00 || $val == 0xff;
|
2007-06-25 19:02:25 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
print "Yes\n";
|
2007-06-25 19:02:25 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
foreach $chip (@{$ns_chips}) {
|
|
|
|
if ($chip->{devid} == $val) {
|
|
|
|
probe_superio($addrreg, $datareg, $chip);
|
|
|
|
return 1;
|
|
|
|
}
|
2007-06-25 19:02:25 +00:00
|
|
|
}
|
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
printf("Found unknown non-standard chip with ID 0x%02x\n", $val);
|
|
|
|
return 1;
|
2007-06-25 19:02:25 +00:00
|
|
|
}
|
|
|
|
|
2002-12-09 03:01:23 +00:00
|
|
|
sub scan_superio
|
|
|
|
{
|
2008-11-30 14:31:03 +00:00
|
|
|
my ($addrreg, $datareg) = @_;
|
|
|
|
my ($val, $found);
|
|
|
|
|
|
|
|
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);
|
|
|
|
FAMILY:
|
|
|
|
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})) {
|
|
|
|
exit_superio($addrreg, $datareg);
|
|
|
|
last FAMILY;
|
|
|
|
}
|
2006-09-01 16:45:50 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
# 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 FAMILY;
|
|
|
|
}
|
|
|
|
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})) {
|
|
|
|
probe_superio($addrreg, $datareg, $chip);
|
|
|
|
$found++;
|
|
|
|
}
|
|
|
|
}
|
2006-09-01 19:22:13 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
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};
|
|
|
|
}
|
2006-09-05 12:09:30 +00:00
|
|
|
|
2008-11-30 14:31:03 +00:00
|
|
|
exit_superio($addrreg, $datareg);
|
|
|
|
last FAMILY;
|
|
|
|
}
|
|
|
|
$| = 0;
|
2002-12-09 03:01:23 +00:00
|
|
|
}
|
|
|
|
|
1999-02-18 18:09:14 +00:00
|
|
|
|
2008-11-27 21:41:28 +00:00
|
|
|
sub scan_cpu
|
2006-10-15 09:30:45 +00:00
|
|
|
{
|
2008-11-30 14:31:03 +00:00
|
|
|
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(undef, $entry->{driver}, $new_hash);
|
|
|
|
} else {
|
|
|
|
print "No\n";
|
|
|
|
}
|
2006-10-15 09:30:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-02-18 00:19:19 +00:00
|
|
|
##################
|
|
|
|
# CHIP DETECTION #
|
|
|
|
##################
|
|
|
|
|
2008-11-22 18:04:50 +00:00
|
|
|
# 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
|
2006-06-18 16:53:02 +00:00
|
|
|
sub chip_special_cases
|
|
|
|
{
|
2008-11-22 18:04:50 +00:00
|
|
|
# Some chip to driver mappings depend on the environment
|
|
|
|
foreach my $chip (@chip_ids) {
|
|
|
|
if (ref($chip->{driver}) eq 'CODE') {
|
|
|
|
$chip->{driver} = $chip->{driver}->();
|
|
|
|
}
|
2007-10-19 13:29:56 +00:00
|
|
|
}
|
2008-11-30 09:15:32 +00:00
|
|
|
|
|
|
|
# Also fill the fake driver name of non-hwmon chips
|
|
|
|
foreach my $chip (@non_hwmon_chip_ids) {
|
|
|
|
$chip->{driver} = "not-a-sensor";
|
|
|
|
}
|
2006-06-18 16:53:02 +00:00
|
|
|
}
|
|
|
|
|
1999-02-18 18:09:14 +00:00
|
|
|
# Each function returns a confidence value. The higher this value, the more
|
2008-11-25 13:27:10 +00:00
|
|
|
# sure we are about this chip. This may help overrule false positives,
|
|
|
|
# although we also attempt to prevent false positives in the first place.
|
1999-02-18 21:14:48 +00:00
|
|
|
|
|
|
|
# Each function returns a list. The first element is the confidence value;
|
2008-05-22 12:01:33 +00:00
|
|
|
# Each element after it is an SMBus address. In this way, we can detect
|
1999-02-18 21:14:48 +00:00
|
|
|
# chips with several SMBus addresses. The SMBus address for which the
|
|
|
|
# function was called is never returned.
|
1999-02-18 18:09:14 +00:00
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# All I2C detection functions below take at least 2 parameters:
|
|
|
|
# $_[0]: Reference to the file descriptor to access the chip
|
2000-10-18 00:34:07 +00:00
|
|
|
# $_[1]: Address
|
2008-11-24 16:51:00 +00:00
|
|
|
# Some of these functions which can detect more than one type of device,
|
|
|
|
# take a third parameter:
|
|
|
|
# $_[2]: Chip to detect
|
|
|
|
|
2000-10-18 00:34:07 +00:00
|
|
|
# Registers used: 0x58
|
|
|
|
sub mtp008_detect
|
|
|
|
{
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($file, $addr) = @_;
|
2008-05-28 09:32:41 +00:00
|
|
|
return if i2c_smbus_read_byte_data($file, 0x58) != 0xac;
|
2008-11-24 17:28:25 +00:00
|
|
|
return 3;
|
2000-10-18 00:34:07 +00:00
|
|
|
}
|
2008-05-22 12:01:33 +00:00
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = LM78, 2 = LM79
|
1999-02-18 18:09:14 +00:00
|
|
|
# Registers used:
|
1999-02-18 21:14:48 +00:00
|
|
|
# 0x40: Configuration
|
1999-02-18 18:09:14 +00:00
|
|
|
# 0x48: Full I2C Address
|
|
|
|
# 0x49: Device ID
|
|
|
|
sub lm78_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
1999-02-18 18:09:14 +00:00
|
|
|
my $reg;
|
2008-05-22 12:01:33 +00:00
|
|
|
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);
|
2008-11-24 14:56:18 +00:00
|
|
|
return unless ($chip == 0 and ($reg == 0x00 or $reg == 0x20 or $reg == 0x40)) or
|
1999-02-19 02:30:17 +00:00
|
|
|
($chip == 2 and ($reg & 0xfe) == 0xc0);
|
2008-09-10 07:22:06 +00:00
|
|
|
|
|
|
|
# Explicitly prevent misdetection of Winbond chips
|
|
|
|
$reg = i2c_smbus_read_byte_data($file, 0x4f);
|
|
|
|
return if $reg == 0xa3 || $reg == 0x5c;
|
|
|
|
|
2008-11-24 17:28:25 +00:00
|
|
|
return 6;
|
1999-02-18 18:09:14 +00:00
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = LM75, 1 = DS75
|
1999-02-18 18:09:14 +00:00
|
|
|
# Registers used:
|
2004-04-14 17:21:26 +00:00
|
|
|
# 0x00: Temperature
|
1999-02-18 18:09:14 +00:00
|
|
|
# 0x01: Configuration
|
1999-08-28 19:10:27 +00:00
|
|
|
# 0x02: Hysteresis
|
1999-02-18 18:09:14 +00:00
|
|
|
# 0x03: Overtemperature Shutdown
|
2004-07-01 21:23:09 +00:00
|
|
|
# 0x04-0x07: No registers
|
2004-07-02 21:59:30 +00:00
|
|
|
# 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
|
2004-07-01 21:23:09 +00:00
|
|
|
# documented.
|
2004-07-02 21:59:30 +00:00
|
|
|
# Note that register 0x00 may change, so we can't use the modulo trick on it.
|
2007-04-03 12:55:30 +00:00
|
|
|
# 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.
|
2008-05-11 17:12:29 +00:00
|
|
|
# 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.
|
1999-02-18 18:09:14 +00:00
|
|
|
sub lm75_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
1999-02-18 18:09:14 +00:00
|
|
|
my $i;
|
2008-05-11 17:12:29 +00:00
|
|
|
my $cur = i2c_smbus_read_byte_data($file, 0x00);
|
2008-05-22 12:01:33 +00:00
|
|
|
my $conf = i2c_smbus_read_byte_data($file, 0x01);
|
2004-07-02 21:59:30 +00:00
|
|
|
|
2008-05-28 07:26:11 +00:00
|
|
|
my $hyst = i2c_smbus_read_byte_data($file, 0x02, NO_CACHE);
|
2007-04-03 12:55:30 +00:00
|
|
|
my $maxreg = $chip == 1 ? 0x0f : 0x07;
|
|
|
|
for $i (0x04 .. $maxreg) {
|
2008-05-28 07:26:11 +00:00
|
|
|
return if i2c_smbus_read_byte_data($file, $i, NO_CACHE) != $hyst;
|
2007-04-03 12:55:30 +00:00
|
|
|
}
|
2004-07-01 21:23:09 +00:00
|
|
|
|
2008-05-28 07:26:11 +00:00
|
|
|
my $os = i2c_smbus_read_byte_data($file, 0x03, NO_CACHE);
|
2007-04-03 12:55:30 +00:00
|
|
|
for $i (0x04 .. $maxreg) {
|
2008-05-28 07:26:11 +00:00
|
|
|
return if i2c_smbus_read_byte_data($file, $i, NO_CACHE) != $os;
|
2007-04-03 12:55:30 +00:00
|
|
|
}
|
2004-07-02 21:59:30 +00:00
|
|
|
|
2007-04-03 12:55:30 +00:00
|
|
|
if ($chip == 0) {
|
|
|
|
for ($i = 8; $i <= 248; $i += 40) {
|
|
|
|
return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf
|
2008-05-11 17:12:29 +00:00
|
|
|
or i2c_smbus_read_byte_data($file, $i + 0x02) != $hyst
|
|
|
|
or i2c_smbus_read_byte_data($file, $i + 0x03) != $os;
|
2007-04-03 12:55:30 +00:00
|
|
|
}
|
1999-02-18 18:09:14 +00:00
|
|
|
}
|
2004-07-02 21:59:30 +00:00
|
|
|
|
2003-10-13 20:09:52 +00:00
|
|
|
# All registers hold the same value, obviously a misdetection
|
2008-05-11 17:12:29 +00:00
|
|
|
return if $conf == $cur and $cur == $hyst and $cur == $os;
|
2004-07-02 21:59:30 +00:00
|
|
|
|
|
|
|
# Unused bits
|
2007-04-03 12:55:30 +00:00
|
|
|
return if $chip == 0 and ($conf & 0xe0);
|
|
|
|
return if $chip == 1 and ($conf & 0x80);
|
2004-07-02 21:59:30 +00:00
|
|
|
|
2003-07-02 09:06:51 +00:00
|
|
|
# Most probable value ranges
|
2004-07-02 21:59:30 +00:00
|
|
|
return 6 if $cur <= 100 and ($hyst >= 10 && $hyst <= 125)
|
|
|
|
and ($os >= 20 && $os <= 127) and $hyst < $os;
|
2003-10-11 13:35:01 +00:00
|
|
|
return 3;
|
1999-02-18 18:09:14 +00:00
|
|
|
}
|
2004-04-14 17:21:26 +00:00
|
|
|
|
2004-07-01 21:23:09 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x00: Temperature
|
|
|
|
# 0x01: Configuration
|
|
|
|
# 0x02: Hysteresis
|
|
|
|
# 0x03: Overtemperature Shutdown
|
|
|
|
# 0x04: Low limit
|
|
|
|
# 0x05: High limit
|
2008-05-11 17:12:29 +00:00
|
|
|
# 0x06-0x07: No registers
|
2004-07-02 21:59:30 +00:00
|
|
|
# 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.
|
2008-05-11 17:12:29 +00:00
|
|
|
# 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.
|
2004-07-01 21:23:09 +00:00
|
|
|
sub lm77_detect
|
|
|
|
{
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($file, $addr) = @_;
|
2008-11-24 16:51:00 +00:00
|
|
|
my $i;
|
2008-05-11 17:12:29 +00:00
|
|
|
my $cur = i2c_smbus_read_byte_data($file, 0x00);
|
2008-05-22 12:01:33 +00:00
|
|
|
my $conf = i2c_smbus_read_byte_data($file, 0x01);
|
2008-05-11 17:12:29 +00:00
|
|
|
my $hyst = i2c_smbus_read_byte_data($file, 0x02);
|
|
|
|
my $os = i2c_smbus_read_byte_data($file, 0x03);
|
2004-07-02 21:59:30 +00:00
|
|
|
|
2008-05-28 07:26:11 +00:00
|
|
|
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;
|
2004-07-02 21:59:30 +00:00
|
|
|
|
2008-05-28 07:26:11 +00:00
|
|
|
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;
|
2004-07-02 21:59:30 +00:00
|
|
|
|
2007-04-03 12:55:30 +00:00
|
|
|
for ($i = 8; $i <= 248; $i += 40) {
|
2004-07-02 21:59:30 +00:00
|
|
|
return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf;
|
2008-05-11 17:12:29 +00:00
|
|
|
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;
|
2004-07-01 21:23:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# All registers hold the same value, obviously a misdetection
|
2008-05-11 17:12:29 +00:00
|
|
|
return if $conf == $cur and $cur == $hyst
|
2004-07-02 21:59:30 +00:00
|
|
|
and $cur == $os and $cur == $low and $cur == $high;
|
|
|
|
|
|
|
|
# Unused bits
|
|
|
|
return if ($conf & 0xe0)
|
2008-05-11 17:12:29 +00:00
|
|
|
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
|
|
|
|
$cur = i2c_smbus_read_word_data($file, 0x00);
|
|
|
|
return if $cur < 0;
|
|
|
|
$hyst = i2c_smbus_read_word_data($file, 0x02);
|
|
|
|
return if $hyst < 0;
|
|
|
|
$os = i2c_smbus_read_word_data($file, 0x03);
|
|
|
|
return if $os < 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;
|
2004-07-02 21:59:30 +00:00
|
|
|
|
2004-07-03 06:59:11 +00:00
|
|
|
$cur /= 16;
|
|
|
|
$hyst /= 16;
|
|
|
|
$os /= 16;
|
|
|
|
$high /= 16;
|
|
|
|
$low /= 16;
|
2004-07-02 21:59:30 +00:00
|
|
|
|
2004-07-01 21:23:09 +00:00
|
|
|
# Most probable value ranges
|
2004-07-02 21:59:30 +00:00
|
|
|
return 6 if $cur <= 100 and $hyst <= 40
|
2004-07-03 06:59:11 +00:00
|
|
|
and ($os >= 20 && $os <= 127) and ($high >= 20 && $high <= 127);
|
2004-07-02 21:59:30 +00:00
|
|
|
return 3;
|
2004-07-01 21:23:09 +00:00
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = LM92, 1 = LM76, 2 = MAX6633/MAX6634/MAX6635
|
2004-04-14 17:21:26 +00:00
|
|
|
# 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.
|
2008-05-11 17:12:29 +00:00
|
|
|
# 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.
|
2004-04-14 17:21:26 +00:00
|
|
|
sub lm92_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2004-04-14 17:21:26 +00:00
|
|
|
|
|
|
|
my $conf = i2c_smbus_read_byte_data($file, 0x01);
|
2008-05-11 17:12:29 +00:00
|
|
|
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);
|
2004-04-14 17:21:26 +00:00
|
|
|
|
2006-11-14 13:04:41 +00:00
|
|
|
return if $conf == 0 and $hyst == 0 and $crit == 0
|
|
|
|
and $low == 0 and $high == 0;
|
|
|
|
|
2008-05-11 17:12:29 +00:00
|
|
|
# Unused bits
|
2004-04-14 17:21:26 +00:00
|
|
|
return if ($chip == 0 || $chip == 1)
|
|
|
|
and ($conf & 0xE0);
|
|
|
|
|
2008-05-11 17:12:29 +00:00
|
|
|
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;
|
2004-04-14 17:21:26 +00:00
|
|
|
}
|
2008-05-22 12:01:33 +00:00
|
|
|
|
2008-05-11 17:12:29 +00:00
|
|
|
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;
|
|
|
|
|
2004-04-14 17:21:26 +00:00
|
|
|
foreach my $temp ($hyst, $crit, $low, $high) {
|
|
|
|
return if $chip == 2 and ($temp & 0x7F00);
|
|
|
|
return if $chip != 2 and ($temp & 0x0700);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 4 if $chip == 0;
|
|
|
|
return 2;
|
|
|
|
}
|
2008-05-22 12:01:33 +00:00
|
|
|
|
2000-11-26 23:07:17 +00:00
|
|
|
# Registers used:
|
2003-12-02 20:57:02 +00:00
|
|
|
# 0xAA: Temperature
|
|
|
|
# 0xA1: High limit
|
|
|
|
# 0xA2: Low limit
|
2008-05-11 17:12:29 +00:00
|
|
|
# 0xA8: Counter
|
|
|
|
# 0xA9: Slope
|
2000-11-26 23:07:17 +00:00
|
|
|
# 0xAC: Configuration
|
2005-01-19 20:38:58 +00:00
|
|
|
# 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).
|
2008-05-11 17:12:29 +00:00
|
|
|
# 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.
|
2000-11-26 23:07:17 +00:00
|
|
|
sub ds1621_detect
|
|
|
|
{
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($file, $addr) = @_;
|
2008-05-11 17:12:29 +00:00
|
|
|
|
|
|
|
my $conf = i2c_smbus_read_byte_data($file, 0xAC);
|
|
|
|
return if ($conf & 0x10);
|
|
|
|
|
|
|
|
my $counter = i2c_smbus_read_byte_data($file, 0xA8);
|
|
|
|
my $slope = i2c_smbus_read_byte_data($file, 0xA9);
|
|
|
|
return if ($slope != 0x10 || $counter > $slope);
|
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
my $temp = i2c_smbus_read_word_data($file, 0xAA);
|
2008-05-11 20:56:25 +00:00
|
|
|
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.
|
2008-05-22 12:01:33 +00:00
|
|
|
my $high = i2c_smbus_read_word_data($file, 0xA1);
|
2008-05-11 17:12:29 +00:00
|
|
|
return if $high < 0 || ($high & 0x7f00);
|
2008-05-22 12:01:33 +00:00
|
|
|
my $low = i2c_smbus_read_word_data($file, 0xA2);
|
2008-05-11 17:12:29 +00:00
|
|
|
return if $low < 0 || ($low & 0x7f00);
|
|
|
|
|
2006-01-17 07:34:49 +00:00
|
|
|
return if ($temp == 0 && $high == 0 && $low == 0 && $conf == 0);
|
2008-05-11 17:12:29 +00:00
|
|
|
|
|
|
|
return 3;
|
2000-11-26 23:07:17 +00:00
|
|
|
}
|
1999-02-18 18:09:14 +00:00
|
|
|
|
|
|
|
# Registers used:
|
2004-02-11 22:07:02 +00:00
|
|
|
# 0x00: Configuration register
|
1999-02-18 18:09:14 +00:00
|
|
|
# 0x02: Interrupt state register
|
2004-02-11 22:07:02 +00:00
|
|
|
# 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.
|
1999-02-18 18:09:14 +00:00
|
|
|
sub lm80_detect
|
|
|
|
{
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($file, $addr) = @_;
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($i, $reg);
|
2004-02-11 22:07:02 +00:00
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
return if (i2c_smbus_read_byte_data($file, 0x00) & 0x80) != 0;
|
|
|
|
return if (i2c_smbus_read_byte_data($file, 0x02) & 0xc0) != 0;
|
2004-02-11 22:07:02 +00:00
|
|
|
|
1999-02-18 18:09:14 +00:00
|
|
|
for ($i = 0x2a; $i <= 0x3d; $i++) {
|
2008-05-22 12:01:33 +00:00
|
|
|
$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;
|
1999-02-18 18:09:14 +00:00
|
|
|
}
|
2008-05-22 12:01:33 +00:00
|
|
|
|
2004-02-11 22:07:02 +00:00
|
|
|
# Refine a bit by checking wether limits are in the correct order
|
|
|
|
# (min<max for voltages, hyst<max for temperature). Since it is still
|
|
|
|
# possible that the chip is an LM80 with limits not properly set,
|
|
|
|
# a few "errors" are tolerated.
|
|
|
|
my $confidence = 0;
|
|
|
|
for ($i = 0x2a; $i <= 0x3a; $i++) {
|
|
|
|
$confidence++
|
2008-05-22 12:01:33 +00:00
|
|
|
if i2c_smbus_read_byte_data($file, $i) < i2c_smbus_read_byte_data($file, $i+1);
|
2003-11-21 23:12:04 +00:00
|
|
|
}
|
2004-02-11 22:07:02 +00:00
|
|
|
# hot temp<OS temp
|
|
|
|
$confidence++
|
2008-05-22 12:01:33 +00:00
|
|
|
if i2c_smbus_read_byte_data($file, 0x38) < i2c_smbus_read_byte_data($file, 0x3a);
|
2004-02-11 22:07:02 +00:00
|
|
|
|
|
|
|
# Negative temperature limits are unlikely.
|
|
|
|
for ($i = 0x3a; $i <= 0x3d; $i++) {
|
2008-05-22 12:01:33 +00:00
|
|
|
$confidence++ if (i2c_smbus_read_byte_data($file, $i) & 0x80) == 0;
|
2004-02-11 22:07:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# $confidence is between 0 and 14
|
|
|
|
$confidence = ($confidence >> 1) - 4;
|
|
|
|
# $confidence is now between -4 and 3
|
|
|
|
|
|
|
|
return unless $confidence > 0;
|
|
|
|
|
|
|
|
return $confidence;
|
1999-02-18 18:09:14 +00:00
|
|
|
}
|
2002-06-30 20:34:35 +00:00
|
|
|
|
2003-07-03 17:28:16 +00:00
|
|
|
# Registers used:
|
2003-08-07 13:03:25 +00:00
|
|
|
# 0x02: Status 1
|
2003-07-19 22:09:39 +00:00
|
|
|
# 0x03: Configuration
|
2003-07-03 17:28:16 +00:00
|
|
|
# 0x04: Company ID of LM84
|
2003-08-07 13:03:25 +00:00
|
|
|
# 0x35: Status 2
|
2003-07-03 17:28:16 +00:00
|
|
|
# 0xfe: Manufacturer ID
|
2003-07-19 22:09:39 +00:00
|
|
|
# 0xff: Chip ID / die revision
|
|
|
|
# We can use the LM84 Company ID register because the LM83 and the LM82 are
|
|
|
|
# compatible with the LM84.
|
2003-08-07 13:03:25 +00:00
|
|
|
# The LM83 chip ID is missing from the datasheet and was contributed by
|
2005-06-12 07:36:12 +00:00
|
|
|
# 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.
|
2003-07-03 17:28:16 +00:00
|
|
|
sub lm83_detect
|
|
|
|
{
|
2008-11-24 15:27:26 +00:00
|
|
|
my ($file, $addr) = @_;
|
2008-05-22 12:01:33 +00:00
|
|
|
return if i2c_smbus_read_byte_data($file, 0xfe) != 0x01;
|
|
|
|
my $chipid = i2c_smbus_read_byte_data($file, 0xff);
|
2005-06-12 07:36:12 +00:00
|
|
|
return if $chipid != 0x01 && $chipid != 0x03;
|
2003-08-07 13:03:25 +00:00
|
|
|
|
|
|
|
my $confidence = 4;
|
|
|
|
$confidence++
|
2008-05-22 12:01:33 +00:00
|
|
|
if (i2c_smbus_read_byte_data($file, 0x02) & 0xa8) == 0x00;
|
2003-08-07 13:03:25 +00:00
|
|
|
$confidence++
|
2008-05-22 12:01:33 +00:00
|
|
|
if (i2c_smbus_read_byte_data($file, 0x03) & 0x41) == 0x00;
|
2003-08-07 13:03:25 +00:00
|
|
|
$confidence++
|
2008-05-22 12:01:33 +00:00
|
|
|
if i2c_smbus_read_byte_data($file, 0x04) == 0x00;
|
2003-08-07 13:03:25 +00:00
|
|
|
$confidence++
|
2008-05-22 12:01:33 +00:00
|
|
|
if (i2c_smbus_read_byte_data($file, 0x35) & 0x48) == 0x00;
|
2003-08-07 13:03:25 +00:00
|
|
|
|
|
|
|
return $confidence;
|
2003-07-03 17:28:16 +00:00
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# 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
|
2003-07-07 10:31:41 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x03: Configuration
|
2004-06-04 22:18:30 +00:00
|
|
|
# 0x04: Conversion rate
|
2003-07-07 10:31:41 +00:00
|
|
|
# 0xfe: Manufacturer ID
|
|
|
|
# 0xff: Chip ID / die revision
|
|
|
|
sub lm90_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2003-08-30 20:53:29 +00:00
|
|
|
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);
|
2004-06-04 22:18:30 +00:00
|
|
|
my $rate = i2c_smbus_read_byte_data($file, 0x04);
|
2003-08-30 20:53:29 +00:00
|
|
|
|
2003-07-19 22:09:39 +00:00
|
|
|
if ($chip == 0) {
|
2003-08-30 20:53:29 +00:00
|
|
|
return if ($conf & 0x2a) != 0;
|
2004-06-04 22:18:30 +00:00
|
|
|
return if $rate > 0x09;
|
2004-04-23 16:25:56 +00:00
|
|
|
return if $mid != 0x01; # National Semiconductor
|
2003-08-30 20:53:29 +00:00
|
|
|
return 8 if $cid == 0x21; # LM90
|
2004-06-04 22:18:30 +00:00
|
|
|
return 6 if ($cid & 0x0f) == 0x20;
|
2003-07-19 22:09:39 +00:00
|
|
|
}
|
|
|
|
if ($chip == 1) {
|
2003-08-30 20:53:29 +00:00
|
|
|
return if ($conf & 0x2a) != 0;
|
2004-06-04 22:18:30 +00:00
|
|
|
return if $rate > 0x09;
|
2004-04-23 16:25:56 +00:00
|
|
|
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
|
2004-06-04 22:18:30 +00:00
|
|
|
return 6 if ($cid & 0x0f) == 0x30;
|
2003-07-19 22:09:39 +00:00
|
|
|
}
|
|
|
|
if ($chip == 2) {
|
2003-08-30 20:53:29 +00:00
|
|
|
return if ($conf & 0x2a) != 0;
|
2004-06-04 22:18:30 +00:00
|
|
|
return if $rate > 0x09;
|
2004-04-23 16:25:56 +00:00
|
|
|
return if $mid != 0x01; # National Semiconductor
|
2003-08-30 20:53:29 +00:00
|
|
|
return 8 if $cid == 0x11; # LM86
|
2004-06-04 22:18:30 +00:00
|
|
|
return 6 if ($cid & 0xf0) == 0x10;
|
2003-08-30 20:53:29 +00:00
|
|
|
}
|
|
|
|
if ($chip == 3) {
|
|
|
|
return if ($conf & 0x3f) != 0;
|
2004-06-04 22:18:30 +00:00
|
|
|
return if $rate > 0x0a;
|
2004-04-23 16:25:56 +00:00
|
|
|
return if $mid != 0x41; # Analog Devices
|
2008-05-25 10:07:25 +00:00
|
|
|
return 6 if ($cid & 0xf0) == 0x40; # ADM1032
|
2003-07-19 22:09:39 +00:00
|
|
|
}
|
2008-05-28 12:36:57 +00:00
|
|
|
if ($chip == 4) {
|
|
|
|
return if ($conf & 0x07) != 0;
|
|
|
|
return if $rate > 0x07;
|
|
|
|
return if $mid != 0x4d; # Maxim
|
|
|
|
return if $cid != 0x08; # MAX6654/MAX6690
|
|
|
|
return 8;
|
|
|
|
}
|
2004-04-10 16:45:48 +00:00
|
|
|
if ($chip == 5) {
|
|
|
|
return if ($conf & 0x1b) != 0;
|
2004-06-04 22:18:30 +00:00
|
|
|
return if $rate > 0x0a;
|
2004-04-10 16:45:48 +00:00
|
|
|
return if $mid != 0x41; # Analog Devices
|
2008-06-15 08:42:14 +00:00
|
|
|
return 8 if $cid == 0x51; # ADT7461
|
2004-04-10 16:45:48 +00:00
|
|
|
}
|
2006-12-02 22:05:42 +00:00
|
|
|
if ($chip == 6) {
|
|
|
|
return if ($conf & 0x3f) != 0;
|
|
|
|
return if $rate > 0x07;
|
|
|
|
return if $mid != 0x4d; # Maxim
|
|
|
|
return if $cid != 0x59; # MAX6648/MAX6692
|
|
|
|
return 8;
|
2008-05-22 12:01:33 +00:00
|
|
|
}
|
2007-05-22 11:31:51 +00:00
|
|
|
if ($chip == 7) {
|
|
|
|
return if ($conf & 0x03) != 0;
|
|
|
|
return if $rate > 0x07;
|
|
|
|
return if $mid != 0x4d; # Maxim
|
|
|
|
return if $cid != 0x01; # MAX6680/MAX6681
|
2008-05-25 10:07:25 +00:00
|
|
|
return 8;
|
2007-05-22 11:31:51 +00:00
|
|
|
}
|
2007-08-12 19:41:33 +00:00
|
|
|
if ($chip == 8) {
|
|
|
|
return if ($conf & 0x2a) != 0;
|
|
|
|
return if $rate > 0x09;
|
|
|
|
return if $mid != 0x5c; # Winbond
|
|
|
|
return if $cid != 0x00; # W83L771W/G
|
|
|
|
return 6;
|
|
|
|
}
|
2007-10-28 14:20:53 +00:00
|
|
|
if ($chip == 9) {
|
|
|
|
return if ($conf & 0x1B) != 0;
|
|
|
|
return if $rate > 0x0F;
|
|
|
|
return if $mid != 0x55; # Texas Instruments
|
2008-08-20 18:02:22 +00:00
|
|
|
return if $cid != 0x11; # TMP401
|
2008-05-25 10:07:25 +00:00
|
|
|
return 8;
|
2007-10-28 14:20:53 +00:00
|
|
|
}
|
2008-08-20 18:02:22 +00:00
|
|
|
if ($chip == 10) {
|
|
|
|
return if ($conf & 0x1B) != 0;
|
|
|
|
return if $rate > 0x0F;
|
|
|
|
return if $mid != 0x55; # Texas Instruments
|
2008-08-20 18:03:52 +00:00
|
|
|
return 6 if ($addr == 0x4c && $cid == 0x12); # TMP411A
|
2008-08-20 18:02:22 +00:00
|
|
|
return 6 if ($addr == 0x4d && $cid == 0x13); # TMP411B
|
|
|
|
return 6 if ($addr == 0x4e && $cid == 0x10); # TMP411C
|
|
|
|
return;
|
|
|
|
}
|
2003-07-19 22:09:39 +00:00
|
|
|
return;
|
2003-07-07 10:31:41 +00:00
|
|
|
}
|
|
|
|
|
2008-05-25 10:07:25 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x03: Configuration (no low nibble)
|
|
|
|
# 0x04: Conversion rate
|
|
|
|
# 0xfe: Manufacturer ID
|
|
|
|
# 0xff: no register
|
|
|
|
sub max6657_detect
|
|
|
|
{
|
|
|
|
my ($file, $addr) = @_;
|
2008-05-28 07:26:11 +00:00
|
|
|
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);
|
2008-05-25 10:07:25 +00:00
|
|
|
|
|
|
|
return if $mid != 0x4d; # Maxim
|
|
|
|
return if ($conf & 0x1f) != 0x0d; # No low nibble,
|
|
|
|
# returns previous low nibble
|
|
|
|
return if $cid != 0x4d; # No register, returns previous value
|
|
|
|
|
2008-05-28 07:26:11 +00:00
|
|
|
my $rate = i2c_smbus_read_byte_data($file, 0x04, NO_CACHE);
|
2008-05-25 10:07:25 +00:00
|
|
|
return if $rate > 0x09;
|
|
|
|
|
2008-05-28 07:26:11 +00:00
|
|
|
$cid = i2c_smbus_read_byte_data($file, 0xff, NO_CACHE);
|
|
|
|
$conf = i2c_smbus_read_byte_data($file, 0x03, NO_CACHE);
|
2008-05-25 10:07:25 +00:00
|
|
|
return if ($conf & 0x0f) != $rate; # No low nibble,
|
|
|
|
# returns previous low nibble
|
|
|
|
return if $cid != $rate; # No register, returns previous value
|
|
|
|
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
|
2008-05-28 12:36:57 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x03: Configuration
|
|
|
|
# 0xfe: Manufacturer ID
|
|
|
|
# 0xff: Revision ID
|
|
|
|
sub lm95231_detect
|
|
|
|
{
|
|
|
|
my ($file, $addr) = @_;
|
|
|
|
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);
|
|
|
|
|
|
|
|
return if ($conf & 0x89) != 0;
|
|
|
|
return if $mid != 0x01; # National Semiconductor
|
|
|
|
return if $cid != 0xa1; # LM95231
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 1 = LM63, 2 = F75363SG, 3 = LM64
|
2004-10-09 07:47:36 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0xfe: Manufacturer ID
|
|
|
|
# 0xff: Chip ID / die revision
|
2006-04-01 11:43:55 +00:00
|
|
|
# 0x03: Configuration (two or three unused bits)
|
|
|
|
# 0x16: Alert mask (two or three unused bits)
|
2004-10-09 07:47:36 +00:00
|
|
|
sub lm63_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2004-10-09 07:47:36 +00:00
|
|
|
|
|
|
|
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);
|
2006-04-01 11:43:55 +00:00
|
|
|
|
|
|
|
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
|
2008-04-27 07:08:08 +00:00
|
|
|
|| ($mask & 0x84) != 0x00;
|
|
|
|
} elsif ($chip == 3) {
|
|
|
|
return if $mid != 0x01 # National Semiconductor
|
|
|
|
|| $cid != 0x51; # LM64
|
|
|
|
return if ($conf & 0x18) != 0x00
|
|
|
|
|| ($mask & 0xa4) != 0xa4;
|
2004-10-09 07:47:36 +00:00
|
|
|
}
|
|
|
|
|
2008-04-27 07:08:08 +00:00
|
|
|
return 6;
|
2004-10-09 07:47:36 +00:00
|
|
|
}
|
|
|
|
|
2003-11-08 11:13:46 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x02, 0x03: Fan support
|
2006-12-21 17:56:43 +00:00
|
|
|
# 0x06: Temperature support
|
2003-11-08 11:13:46 +00:00
|
|
|
# 0x07, 0x08, 0x09: Fan config
|
|
|
|
# 0x0d: Manufacturer ID
|
|
|
|
# 0x0e: Chip ID / die revision
|
|
|
|
sub adm1029_detect
|
|
|
|
{
|
2008-11-24 15:27:26 +00:00
|
|
|
my ($file, $addr) = @_;
|
2003-11-08 11:13:46 +00:00
|
|
|
my $mid = i2c_smbus_read_byte_data($file, 0x0d);
|
|
|
|
my $cid = i2c_smbus_read_byte_data($file, 0x0e);
|
2006-12-21 17:56:43 +00:00
|
|
|
my $cfg;
|
2003-11-08 11:13:46 +00:00
|
|
|
|
2008-11-24 15:27:26 +00:00
|
|
|
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;
|
2003-11-08 11:13:46 +00:00
|
|
|
}
|
2008-11-24 15:27:26 +00:00
|
|
|
|
|
|
|
return 7;
|
2003-11-08 11:13:46 +00:00
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = ADM1030, 1 = ADM1031
|
2003-11-08 11:13:46 +00:00
|
|
|
# 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
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2003-11-08 11:13:46 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = ADM1033, 1 = ADM1034
|
2006-08-27 19:51:38 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x3d: Chip ID
|
|
|
|
# 0x3e: Manufacturer ID
|
|
|
|
# 0x3f: Die revision
|
|
|
|
sub adm1034_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2006-08-27 19:51:38 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = ADT7467/ADT7468, 1 = ADT7476, 2 = ADT7462, 3 = ADT7466,
|
|
|
|
# 4 = ADT7470
|
2004-04-10 16:45:48 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x3d: Chip ID
|
|
|
|
# 0x3e: Manufacturer ID
|
|
|
|
# 0x3f: Die revision
|
|
|
|
sub adt7467_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2004-04-10 16:45:48 +00:00
|
|
|
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 != 0x68; # ADT7467
|
|
|
|
return if ($drev & 0xf0) != 0x70;
|
2005-10-01 15:34:38 +00:00
|
|
|
return 7 if ($drev == 0x71 || $drev == 0x72);
|
2004-04-10 16:45:48 +00:00
|
|
|
return 5;
|
|
|
|
}
|
2005-11-26 11:28:44 +00:00
|
|
|
if ($chip == 1) {
|
|
|
|
return if $mid != 0x41; # Analog Devices
|
|
|
|
return if $cid != 0x76; # ADT7476
|
|
|
|
return if ($drev & 0xf0) != 0x60;
|
|
|
|
return 7 if ($drev == 0x69);
|
|
|
|
return 5;
|
|
|
|
}
|
2006-08-27 19:51:38 +00:00
|
|
|
if ($chip == 2) {
|
|
|
|
return if $mid != 0x41; # Analog Devices
|
|
|
|
return if $cid != 0x62; # ADT7462
|
|
|
|
return if ($drev & 0xf0) != 0x00;
|
|
|
|
return 7 if ($drev == 0x04);
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
if ($chip == 3) {
|
|
|
|
return if $mid != 0x41; # Analog Devices
|
|
|
|
return if $cid != 0x66; # ADT7466
|
|
|
|
return if ($drev & 0xf0) != 0x00;
|
|
|
|
return 7 if ($drev == 0x02);
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
if ($chip == 4) {
|
|
|
|
return if $mid != 0x41; # Analog Devices
|
|
|
|
return if $cid != 0x70; # ADT7470
|
|
|
|
return if ($drev & 0xf0) != 0x00;
|
|
|
|
return 7 if ($drev == 0x00);
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = ADT7473, 1 = ADT7475
|
2006-08-27 19:51:38 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x3d: Chip ID
|
|
|
|
# 0x3e: Manufacturer ID
|
|
|
|
sub adt7473_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2006-08-27 19:51:38 +00:00
|
|
|
my $mid = i2c_smbus_read_byte_data($file, 0x3e);
|
|
|
|
my $cid = i2c_smbus_read_byte_data($file, 0x3d);
|
|
|
|
|
|
|
|
if ($chip == 0) {
|
|
|
|
return if $mid != 0x41; # Analog Devices
|
|
|
|
return if $cid != 0x73; # ADT7473
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
if ($chip == 1) {
|
|
|
|
return if $mid != 0x41; # Analog Devices
|
|
|
|
return if $cid != 0x75; # ADT7475
|
|
|
|
return 5;
|
|
|
|
}
|
2004-04-10 16:45:48 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = aSC7512, 1 = aSC7611, 2 = aSC7621
|
2006-12-09 21:19:20 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x3e: Manufacturer ID (0x61)
|
|
|
|
# 0x3f: Version
|
|
|
|
sub andigilog_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2006-12-09 21:19:20 +00:00
|
|
|
my $mid = i2c_smbus_read_byte_data($file, 0x3e);
|
|
|
|
my $cid = i2c_smbus_read_byte_data($file, 0x3f);
|
|
|
|
|
|
|
|
return if ($mid != 0x61);
|
|
|
|
|
|
|
|
if ($chip == 0) {
|
|
|
|
return if $cid != 0x62;
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($chip == 1) {
|
|
|
|
return if $cid != 0x69;
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($chip == 2) {
|
2008-06-08 10:19:13 +00:00
|
|
|
return if ($cid != 0x6C && $cid != 0x6D);
|
2006-12-09 21:19:20 +00:00
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Registers used:
|
|
|
|
# 0xfe: Manufacturer ID
|
|
|
|
# 0xff: Die Code
|
|
|
|
sub andigilog_aSC7511_detect
|
|
|
|
{
|
2008-11-24 15:27:26 +00:00
|
|
|
my ($file, $addr) = @_;
|
2006-12-09 21:19:20 +00:00
|
|
|
my $mid = i2c_smbus_read_byte_data($file, 0xfe);
|
2006-12-10 10:55:01 +00:00
|
|
|
my $die = i2c_smbus_read_byte_data($file, 0xff);
|
2006-12-09 21:19:20 +00:00
|
|
|
|
2008-11-24 15:27:26 +00:00
|
|
|
return if $mid != 0x61; # Andigilog
|
|
|
|
if ($die == 0x0) {
|
|
|
|
return 3;
|
|
|
|
} else {
|
|
|
|
return 1;
|
2006-12-09 21:19:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = LM85, 1 = LM96000, 2 = ADM1027, 3 = ADT7463,
|
|
|
|
# 4 = EMC6D100/101, 5 = EMC6D102, 6 = EMC6D103
|
2002-06-30 20:34:35 +00:00
|
|
|
# Registers used: 0x3e == Vendor register.
|
2004-04-10 16:45:48 +00:00
|
|
|
# 0x3d == Device ID register (Analog Devices only).
|
2002-06-30 20:34:35 +00:00
|
|
|
# 0x3f == Version/Stepping register.
|
|
|
|
sub lm85_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2008-05-23 10:22:30 +00:00
|
|
|
my $vendor = i2c_smbus_read_byte_data($file, 0x3e);
|
2008-05-22 12:01:33 +00:00
|
|
|
my $verstep = i2c_smbus_read_byte_data($file, 0x3f);
|
2008-05-23 10:22:30 +00:00
|
|
|
|
|
|
|
if ($chip == 0) {
|
|
|
|
return if $vendor != 0x01; # National Semiconductor
|
|
|
|
return if $verstep != 0x60 # LM85 C
|
|
|
|
&& $verstep != 0x62; # LM85 B
|
|
|
|
} elsif ($chip == 1) {
|
|
|
|
return if $vendor != 0x01; # National Semiconductor
|
2008-10-02 11:42:47 +00:00
|
|
|
return if $verstep != 0x68 # LM96000
|
|
|
|
&& $verstep != 0x69; # LM96000
|
2008-05-23 10:22:30 +00:00
|
|
|
} elsif ($chip == 2) {
|
|
|
|
return if $vendor != 0x41; # Analog Devices
|
|
|
|
return if $verstep != 0x60; # ADM1027
|
|
|
|
} elsif ($chip == 3) {
|
|
|
|
return if $vendor != 0x41; # Analog Devices
|
2008-10-02 11:42:47 +00:00
|
|
|
return if $verstep != 0x62 # ADT7463
|
|
|
|
&& $verstep != 0x6a; # ADT7463 C
|
2008-05-23 10:22:30 +00:00
|
|
|
} 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
|
|
|
|
}
|
2004-04-10 16:45:48 +00:00
|
|
|
|
2008-05-24 06:56:33 +00:00
|
|
|
if ($vendor == 0x41) { # Analog Devices
|
2004-04-10 16:45:48 +00:00
|
|
|
return if i2c_smbus_read_byte_data($file, 0x3d) != 0x27;
|
2008-11-24 17:28:25 +00:00
|
|
|
return 8;
|
2004-04-10 16:45:48 +00:00
|
|
|
}
|
|
|
|
|
2008-11-24 17:28:25 +00:00
|
|
|
return 7;
|
2002-06-30 20:34:35 +00:00
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = LM87, 1 = ADM1024
|
2008-11-22 16:05:13 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x3e: Company ID
|
|
|
|
# 0x3f: Revision
|
|
|
|
# 0x40: Configuration
|
2000-07-25 01:07:00 +00:00
|
|
|
sub lm87_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2008-11-22 16:05:13 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
if ($chip == 1) {
|
|
|
|
return if $cid != 0x41; # Analog Devices
|
|
|
|
return if ($rev & 0xf0) != 0x10;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $cfg = i2c_smbus_read_byte_data($file, 0x40);
|
|
|
|
return if ($cfg & 0x80) != 0x00;
|
|
|
|
|
2008-11-24 17:28:25 +00:00
|
|
|
return 7;
|
2000-07-25 01:07:00 +00:00
|
|
|
}
|
2008-05-22 12:01:33 +00:00
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# 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
|
1999-02-18 21:14:48 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x48: Full I2C Address
|
|
|
|
# 0x4a: I2C addresses of emulated LM75 chips
|
|
|
|
# 0x4e: Vendor ID byte selection, and bank selection
|
|
|
|
# 0x4f: Vendor ID
|
2003-07-27 10:37:32 +00:00
|
|
|
# 0x58: Device ID (only when in bank 0)
|
1999-02-22 18:20:35 +00:00
|
|
|
# Note: Fails if the W8378xD is not in bank 0!
|
2003-07-26 09:37:12 +00:00
|
|
|
# Note: Asus chips do not have their I2C address at register 0x48?
|
2003-07-31 07:24:29 +00:00
|
|
|
# AS99127F rev.1 and ASB100 have 0x00, confirmation wanted for
|
|
|
|
# AS99127F rev.2.
|
1999-02-18 21:14:48 +00:00
|
|
|
sub w83781d_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($reg1, $reg2, @res);
|
2003-07-26 09:37:12 +00:00
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
return unless (i2c_smbus_read_byte_data($file, 0x48) == $addr)
|
2003-07-26 09:37:12 +00:00
|
|
|
or ($chip >= 4 && $chip <= 6);
|
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
$reg1 = i2c_smbus_read_byte_data($file, 0x4e);
|
|
|
|
$reg2 = i2c_smbus_read_byte_data($file, 0x4f);
|
2003-07-26 09:37:12 +00:00
|
|
|
if ($chip == 4) { # Asus AS99127F (rev.1)
|
2008-05-22 12:01:33 +00:00
|
|
|
return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xc3) or
|
2003-07-26 09:37:12 +00:00
|
|
|
(($reg1 & 0x80) == 0x80 and $reg2 == 0x12);
|
|
|
|
} elsif ($chip == 6) { # Asus ASB100
|
2008-05-22 12:01:33 +00:00
|
|
|
return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0x94) or
|
2003-07-26 09:37:12 +00:00
|
|
|
(($reg1 & 0x80) == 0x80 and $reg2 == 0x06);
|
|
|
|
} else { # Winbond and Asus AS99127F (rev.2)
|
2008-05-22 12:01:33 +00:00
|
|
|
return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or
|
1999-10-30 21:26:21 +00:00
|
|
|
(($reg1 & 0x80) == 0x80 and $reg2 == 0x5c);
|
|
|
|
}
|
2003-07-26 09:37:12 +00:00
|
|
|
|
1999-02-22 20:40:16 +00:00
|
|
|
return unless ($reg1 & 0x07) == 0x00;
|
2003-07-26 09:37:12 +00:00
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
$reg1 = i2c_smbus_read_byte_data($file, 0x58);
|
2003-07-26 09:37:12 +00:00
|
|
|
return if $chip == 0 and ($reg1 != 0x10 && $reg1 != 0x11);
|
1999-02-22 18:20:35 +00:00
|
|
|
return if $chip == 1 and $reg1 != 0x30;
|
|
|
|
return if $chip == 2 and $reg1 != 0x40;
|
2003-10-25 18:53:48 +00:00
|
|
|
return if $chip == 3 and $reg1 != 0x21;
|
2003-07-26 09:37:12 +00:00
|
|
|
return if $chip == 4 and $reg1 != 0x31;
|
|
|
|
return if $chip == 5 and $reg1 != 0x31;
|
|
|
|
return if $chip == 6 and $reg1 != 0x31;
|
2003-10-28 19:17:04 +00:00
|
|
|
return if $chip == 7 and $reg1 != 0x71;
|
2005-02-08 18:17:01 +00:00
|
|
|
return if $chip == 8 and $reg1 != 0x7a;
|
2008-11-23 15:24:50 +00:00
|
|
|
return if $chip == 9 and ($reg1 != 0x88 && $reg1 != 0xa1);
|
2008-11-23 14:27:22 +00:00
|
|
|
return if $chip == 10 and $reg1 != 0xc1;
|
2005-02-08 18:17:01 +00:00
|
|
|
# Default address is 0x2d
|
|
|
|
@res = ($addr != 0x2d) ? (7) : (8);
|
2008-09-10 07:24:46 +00:00
|
|
|
return @res if $chip >= 9; # No subclients
|
|
|
|
|
|
|
|
$reg1 = i2c_smbus_read_byte_data($file, 0x4a);
|
2003-08-01 09:17:17 +00:00
|
|
|
push @res, ($reg1 & 0x07) + 0x48 unless $reg1 & 0x08;
|
2003-07-26 09:37:12 +00:00
|
|
|
push @res, (($reg1 & 0x70) >> 4) + 0x48 unless ($reg1 & 0x80 or $chip == 2);
|
1999-02-18 21:14:48 +00:00
|
|
|
return @res;
|
|
|
|
}
|
2008-05-22 12:01:33 +00:00
|
|
|
|
2006-04-22 08:53:30 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x0b: Full I2C Address
|
|
|
|
# 0x0c: I2C addresses of emulated LM75 chips
|
2008-05-22 12:01:33 +00:00
|
|
|
# 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)
|
2006-04-22 08:53:30 +00:00
|
|
|
sub w83793_detect
|
|
|
|
{
|
2008-11-24 15:27:26 +00:00
|
|
|
my ($file, $addr) = @_;
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($bank, $reg, @res);
|
2006-04-22 08:53:30 +00:00
|
|
|
|
|
|
|
$bank = i2c_smbus_read_byte_data($file, 0x00);
|
|
|
|
$reg = i2c_smbus_read_byte_data($file, 0x0d);
|
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
return unless (($bank & 0x80) == 0x00 and $reg == 0xa3) or
|
2006-04-22 08:53:30 +00:00
|
|
|
(($bank & 0x80) == 0x80 and $reg == 0x5c);
|
|
|
|
|
|
|
|
$reg = i2c_smbus_read_byte_data($file, 0x0e);
|
2008-11-24 15:27:26 +00:00
|
|
|
return if $reg != 0x7b;
|
2006-04-22 08:53:30 +00:00
|
|
|
|
|
|
|
# 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;
|
|
|
|
}
|
1999-02-18 21:14:48 +00:00
|
|
|
|
2004-12-06 20:18:35 +00:00
|
|
|
# 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;
|
|
|
|
}
|
|
|
|
|
2003-07-27 10:37:32 +00:00
|
|
|
# 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
|
|
|
|
{
|
2008-11-24 16:55:48 +00:00
|
|
|
my ($file, $addr) = @_;
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($vid, $dev);
|
2003-07-27 10:37:32 +00:00
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
$vid = (i2c_smbus_read_byte_data($file, 0x4e) << 8)
|
|
|
|
+ i2c_smbus_read_byte_data($file, 0x4f);
|
|
|
|
$dev = i2c_smbus_read_byte_data($file, 0x58);
|
2003-07-27 10:37:32 +00:00
|
|
|
|
2008-11-24 16:55:48 +00:00
|
|
|
return unless ($dev == 0x56 && $vid == 0x9436) # ASM58
|
|
|
|
|| ($dev == 0x56 && $vid == 0x9406) # AS2K129R
|
|
|
|
|| ($dev == 0x10 && $vid == 0x5ca3);
|
2003-07-27 10:37:32 +00:00
|
|
|
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
|
2008-11-24 17:10:31 +00:00
|
|
|
# Chip to detect: 0 = GL518SM, 1 = GL520SM
|
1999-02-18 21:14:48 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x00: Device ID
|
|
|
|
# 0x01: Revision ID
|
2008-05-22 12:01:33 +00:00
|
|
|
# 0x03: Configuration
|
1999-02-18 21:14:48 +00:00
|
|
|
sub gl518sm_detect
|
|
|
|
{
|
2008-11-24 17:10:31 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
1999-02-18 21:14:48 +00:00
|
|
|
my $reg;
|
|
|
|
|
2008-11-24 17:10:31 +00:00
|
|
|
$reg = i2c_smbus_read_byte_data($file, 0x00);
|
|
|
|
return if $chip == 0 && $reg != 0x80;
|
|
|
|
return if $chip == 1 && $reg != 0x20;
|
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
return unless (i2c_smbus_read_byte_data($file, 0x03) & 0x80) == 0x00;
|
2008-11-24 17:05:33 +00:00
|
|
|
$reg = i2c_smbus_read_byte_data($file, 0x01);
|
|
|
|
return unless $reg == 0x00 or $reg == 0x80;
|
2008-11-24 17:28:25 +00:00
|
|
|
return 6;
|
1999-02-18 21:14:48 +00:00
|
|
|
}
|
|
|
|
|
1999-10-20 02:53:38 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x00: Device ID
|
2008-11-24 17:15:40 +00:00
|
|
|
# 0x03: Configuration
|
1999-10-20 02:53:38 +00:00
|
|
|
# Mediocre detection
|
|
|
|
sub gl525sm_detect
|
|
|
|
{
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($file, $addr) = @_;
|
|
|
|
return unless i2c_smbus_read_byte_data($file, 0x00) == 0x25;
|
2008-11-24 17:15:40 +00:00
|
|
|
return unless (i2c_smbus_read_byte_data($file, 0x03) & 0x80) == 0x00;
|
2008-11-24 17:28:25 +00:00
|
|
|
return 5;
|
1999-10-20 02:53:38 +00:00
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = ADM9240, 1 = DS1780, 2 = LM81
|
1999-02-18 21:14:48 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x3e: Company ID
|
|
|
|
# 0x40: Configuration
|
|
|
|
# 0x48: Full I2C Address
|
|
|
|
sub adm9240_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
1999-03-29 00:58:55 +00:00
|
|
|
my $reg;
|
2008-05-22 12:01:33 +00:00
|
|
|
$reg = i2c_smbus_read_byte_data($file, 0x3e);
|
1999-03-29 00:58:55 +00:00
|
|
|
return unless ($chip == 0 and $reg == 0x23) or
|
1999-08-22 17:52:38 +00:00
|
|
|
($chip == 1 and $reg == 0xda) or
|
|
|
|
($chip == 2 and $reg == 0x01);
|
2008-05-22 12:01:33 +00:00
|
|
|
return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00;
|
|
|
|
return unless i2c_smbus_read_byte_data($file, 0x48) == $addr;
|
|
|
|
|
2008-11-24 17:28:25 +00:00
|
|
|
return 7;
|
1999-08-28 19:10:27 +00:00
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = ADM1022, 1 = THMC50, 2 = ADM1028, 3 = THMC51
|
1999-08-28 19:10:27 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x3e: Company ID
|
|
|
|
# 0x3f: Revision
|
|
|
|
# 0x40: Configuration
|
|
|
|
sub adm1022_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
1999-08-28 19:10:27 +00:00
|
|
|
my $reg;
|
2008-05-22 12:01:33 +00:00
|
|
|
$reg = i2c_smbus_read_byte_data($file, 0x3e);
|
1999-08-28 19:10:27 +00:00
|
|
|
return unless ($chip == 0 and $reg == 0x41) or
|
2004-04-10 17:24:46 +00:00
|
|
|
($chip == 1 and $reg == 0x49) or
|
2008-06-11 14:09:15 +00:00
|
|
|
($chip == 2 and $reg == 0x41) or
|
|
|
|
($chip == 3 and $reg == 0x49);
|
2008-05-22 12:01:33 +00:00
|
|
|
$reg = i2c_smbus_read_byte_data($file, 0x40);
|
2007-07-06 09:54:10 +00:00
|
|
|
return if ($reg & 0x10); # Soft Reset always reads 0
|
|
|
|
return if ($chip != 0 and ($reg & 0x80)); # Reserved on THMC50 and ADM1028
|
2007-04-03 12:55:30 +00:00
|
|
|
$reg = i2c_smbus_read_byte_data($file, 0x3f) & 0xf0;
|
|
|
|
return unless ($chip == 0 and $reg == 0xc0) or
|
|
|
|
($chip == 1 and $reg == 0xc0) or
|
2008-06-11 14:09:15 +00:00
|
|
|
($chip == 2 and $reg == 0xd0) or
|
|
|
|
($chip == 3 and $reg == 0xd0);
|
2008-11-24 17:28:25 +00:00
|
|
|
return 8;
|
1999-02-18 21:14:48 +00:00
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = ADM1025, 1 = NE1619
|
2000-03-19 22:06:54 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x3e: Company ID
|
|
|
|
# 0x3f: Revision
|
|
|
|
# 0x40: Configuration
|
2004-06-27 17:24:11 +00:00
|
|
|
# 0x41: Status 1
|
|
|
|
# 0x42: Status 2
|
2000-03-19 22:06:54 +00:00
|
|
|
sub adm1025_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2000-03-19 22:06:54 +00:00
|
|
|
my $reg;
|
2003-07-26 17:39:41 +00:00
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
$reg = i2c_smbus_read_byte_data($file, 0x3e);
|
2003-07-26 17:39:41 +00:00
|
|
|
return if ($chip == 0) and ($reg != 0x41);
|
|
|
|
return if ($chip == 1) and ($reg != 0xA1);
|
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
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;
|
2003-07-26 17:39:41 +00:00
|
|
|
|
2008-11-24 17:28:25 +00:00
|
|
|
return 8;
|
2000-03-19 22:06:54 +00:00
|
|
|
}
|
|
|
|
|
2003-06-08 21:33:39 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x16: Company ID
|
|
|
|
# 0x17: Revision
|
|
|
|
sub adm1026_detect
|
|
|
|
{
|
2008-11-24 15:27:26 +00:00
|
|
|
my ($file, $addr) = @_;
|
2008-11-24 16:51:00 +00:00
|
|
|
my $reg;
|
2008-05-22 12:01:33 +00:00
|
|
|
$reg = i2c_smbus_read_byte_data($file, 0x16);
|
2003-06-08 21:33:39 +00:00
|
|
|
return unless ($reg == 0x41);
|
2008-05-22 12:01:33 +00:00
|
|
|
return unless (i2c_smbus_read_byte_data($file, 0x17) & 0xf0) == 0x40;
|
2008-11-24 17:28:25 +00:00
|
|
|
return 8;
|
2003-06-08 21:33:39 +00:00
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = ADM1021, 1 = ADM1021A/ADM1023, 2 = MAX1617, 3 = MAX1617A,
|
|
|
|
# 4 = THMC10, 5 = LM84, 6 = GL523, 7 = MC1066
|
1999-02-18 21:14:48 +00:00
|
|
|
# Registers used:
|
1999-10-20 02:13:51 +00:00
|
|
|
# 0x04: Company ID (LM84 only)
|
2003-07-04 08:13:35 +00:00
|
|
|
# 0xfe: Company ID (all but LM84 and MAX1617)
|
|
|
|
# 0xff: Revision (ADM1021, ADM1021A/ADM1023 and MAX1617A)
|
1999-02-18 21:14:48 +00:00
|
|
|
# 0x02: Status
|
2004-03-27 09:19:31 +00:00
|
|
|
# 0x03: Configuration
|
|
|
|
# 0x04: Conversion rate
|
2003-10-10 20:57:40 +00:00
|
|
|
# 0x00-0x01, 0x05-0x08: Temperatures (MAX1617 and LM84)
|
2008-05-22 12:01:33 +00:00
|
|
|
# Note: Especially the MAX1617 has very bad detection; we give it a low
|
1999-02-18 21:14:48 +00:00
|
|
|
# confidence value.
|
|
|
|
sub adm1021_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2004-03-27 09:19:31 +00:00
|
|
|
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
|
2008-05-24 06:56:33 +00:00
|
|
|
if ($chip == 5) { # LM84
|
2004-03-27 09:19:31 +00:00
|
|
|
return if ($status & 0xab) != 0;
|
|
|
|
return if ($conf & 0x7f) != 0;
|
2008-05-24 06:56:33 +00:00
|
|
|
} else {
|
2004-03-27 09:19:31 +00:00
|
|
|
return if ($status & 0x03) != 0;
|
|
|
|
return if ($conf & 0x3f) != 0;
|
|
|
|
return if ($convrate & 0xf8) != 0;
|
|
|
|
}
|
|
|
|
|
2003-10-10 20:57:40 +00:00
|
|
|
# Extra checks for MAX1617 and LM84, since those are often misdetected
|
2004-03-31 19:17:02 +00:00
|
|
|
# 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
|
2004-03-27 09:19:31 +00:00
|
|
|
# by the adm1021 driver.
|
2008-05-24 06:56:33 +00:00
|
|
|
if ($chip == 2 || $chip == 5) {
|
2004-03-27 09:19:31 +00:00
|
|
|
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;
|
|
|
|
|
2003-10-10 20:57:40 +00:00
|
|
|
# Negative temperatures
|
2004-03-31 19:17:02 +00:00
|
|
|
return if ($lte & 0x80) or ($rte & 0x80);
|
2003-10-10 20:57:40 +00:00
|
|
|
# Negative high limits
|
2004-03-31 19:17:02 +00:00
|
|
|
return if ($lhi & 0x80) or ($rhi & 0x80);
|
2003-10-10 20:57:40 +00:00
|
|
|
# Low limits over high limits
|
2008-05-24 06:56:33 +00:00
|
|
|
if ($chip != 5) { # LM84 doesn't have low limits
|
2008-05-28 09:32:41 +00:00
|
|
|
$llo -= 256 if ($llo & 0x80);
|
|
|
|
$rlo -= 256 if ($rlo & 0x80);
|
2004-03-31 19:17:02 +00:00
|
|
|
return if ($llo > $lhi) or ($rlo > $rhi);
|
2004-03-27 09:19:31 +00:00
|
|
|
}
|
2003-10-10 20:57:40 +00:00
|
|
|
}
|
2004-03-27 09:19:31 +00:00
|
|
|
|
2004-03-31 19:17:02 +00:00
|
|
|
return 3 if ($chip == 2) or ($chip == 5);
|
2003-07-04 08:13:35 +00:00
|
|
|
return 7 if $chip <= 3;
|
2003-10-11 13:35:01 +00:00
|
|
|
return 5;
|
1999-02-18 21:14:48 +00:00
|
|
|
}
|
1999-02-17 20:55:23 +00:00
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = MAX1668, 1 = MAX1805, 2 = MAX1989
|
2004-05-15 11:32:19 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0xfe: Company ID
|
|
|
|
# 0xff: Device ID
|
2007-04-03 12:55:30 +00:00
|
|
|
sub max1668_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2007-04-03 12:55:30 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = MAX1619, 1 = MAX1618
|
2007-04-03 12:55:30 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0xfe: Company ID
|
|
|
|
# 0xff: Device ID
|
2004-05-15 11:32:19 +00:00
|
|
|
# 0x02: Status
|
|
|
|
# 0x03: Configuration
|
|
|
|
# 0x04: Conversion rate
|
|
|
|
sub max1619_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2004-05-15 11:32:19 +00:00
|
|
|
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);
|
|
|
|
|
2008-09-19 15:05:28 +00:00
|
|
|
if ($chip == 0) { # MAX1619
|
|
|
|
return if $man_id != 0x4D
|
|
|
|
or $dev_id != 0x04
|
|
|
|
or ($conf & 0x03)
|
|
|
|
or ($status & 0x61)
|
|
|
|
or $convrate >= 8;
|
|
|
|
}
|
|
|
|
if ($chip == 1) { # MAX1618
|
|
|
|
return if $man_id != 0x4D
|
|
|
|
or $dev_id != 0x02
|
|
|
|
or ($conf & 0x07)
|
|
|
|
or ($status & 0x63);
|
|
|
|
}
|
2004-05-15 11:32:19 +00:00
|
|
|
|
|
|
|
return 7;
|
|
|
|
}
|
|
|
|
|
2006-01-15 18:19:43 +00:00
|
|
|
# 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;
|
|
|
|
|
2006-01-16 18:12:46 +00:00
|
|
|
return 6;
|
2006-01-15 18:19:43 +00:00
|
|
|
}
|
|
|
|
|
2000-08-06 17:03:09 +00:00
|
|
|
# Registers used:
|
2001-12-19 19:29:31 +00:00
|
|
|
# 0x00: Configuration
|
2000-08-06 17:03:09 +00:00
|
|
|
# 0x48: Full I2C Address
|
|
|
|
# 0x58: Mfr ID
|
2008-11-24 15:27:26 +00:00
|
|
|
# 0x5b: Device ID
|
2008-11-24 15:51:32 +00:00
|
|
|
sub it8712_i2c_detect
|
2000-08-06 17:03:09 +00:00
|
|
|
{
|
2008-11-24 15:27:26 +00:00
|
|
|
my ($file, $addr) = @_;
|
2008-11-24 16:51:00 +00:00
|
|
|
my $reg;
|
2008-05-22 12:01:33 +00:00
|
|
|
return unless i2c_smbus_read_byte_data($file, 0x48) == $addr;
|
2005-05-23 18:20:41 +00:00
|
|
|
return unless (i2c_smbus_read_byte_data($file, 0x00) & 0x90) == 0x10;
|
2008-05-22 12:01:33 +00:00
|
|
|
return unless i2c_smbus_read_byte_data($file, 0x58) == 0x90;
|
2008-11-24 15:27:26 +00:00
|
|
|
return if i2c_smbus_read_byte_data($file, 0x5b) != 0x12;
|
2008-11-24 17:28:25 +00:00
|
|
|
return 7 + ($addr == 0x2d);
|
2000-08-06 17:03:09 +00:00
|
|
|
}
|
|
|
|
|
1999-03-09 16:19:30 +00:00
|
|
|
# Registers used:
|
2003-08-07 08:51:08 +00:00
|
|
|
# 0-63: SPD Data and Checksum
|
1999-03-09 16:19:30 +00:00
|
|
|
sub eeprom_detect
|
|
|
|
{
|
2007-06-30 15:21:46 +00:00
|
|
|
my ($file, $addr) = @_;
|
1999-03-09 16:19:30 +00:00
|
|
|
my $checksum = 0;
|
2003-08-07 08:51:08 +00:00
|
|
|
|
2004-04-18 00:38:28 +00:00
|
|
|
# Check the checksum for validity (works for most DIMMs and RIMMs)
|
2007-06-30 15:21:46 +00:00
|
|
|
for (my $i = 0; $i <= 62; $i++) {
|
|
|
|
$checksum += i2c_smbus_read_byte_data($file, $i);
|
2004-04-18 00:38:28 +00:00
|
|
|
}
|
2007-06-30 15:21:46 +00:00
|
|
|
$checksum &= 255;
|
|
|
|
|
|
|
|
return 8
|
|
|
|
if $checksum == i2c_smbus_read_byte_data($file, 63);
|
2004-04-18 00:38:28 +00:00
|
|
|
|
|
|
|
return;
|
1999-02-23 23:16:09 +00:00
|
|
|
}
|
|
|
|
|
1999-12-29 23:10:48 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x00..0x07: DDC signature
|
|
|
|
sub ddcmonitor_detect
|
|
|
|
{
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($file, $addr) = @_;
|
2005-01-15 11:41:48 +00:00
|
|
|
|
|
|
|
return unless
|
2008-05-22 12:01:33 +00:00
|
|
|
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;
|
2005-01-15 11:41:48 +00:00
|
|
|
|
2007-06-30 15:21:46 +00:00
|
|
|
return 8;
|
1999-12-29 23:10:48 +00:00
|
|
|
}
|
1999-04-08 19:33:03 +00:00
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 0 = Poseidon I, 1 = Poseidon II, 2 = Scylla,
|
|
|
|
# 3 = Hermes, 4 = Heimdal, 5 = Heracles
|
2001-11-09 13:35:56 +00:00
|
|
|
# Registers used:
|
2008-11-22 17:28:30 +00:00
|
|
|
# 0x00-0x02: Identification (3 capital ASCII letters)
|
|
|
|
sub fsc_detect
|
2001-11-09 13:35:56 +00:00
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2008-11-22 17:28:30 +00:00
|
|
|
my $id;
|
2001-11-09 13:35:56 +00:00
|
|
|
|
2008-11-22 17:28:30 +00:00
|
|
|
$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));
|
2003-09-27 08:19:20 +00:00
|
|
|
|
2008-11-22 17:28:30 +00:00
|
|
|
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
|
2007-08-13 20:11:02 +00:00
|
|
|
|
2008-11-24 17:28:25 +00:00
|
|
|
return 8;
|
2007-10-19 09:43:31 +00:00
|
|
|
}
|
|
|
|
|
2004-06-12 16:22:20 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x3E: Manufacturer ID
|
|
|
|
# 0x3F: Version/Stepping
|
|
|
|
sub lm93_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr) = @_;
|
2004-06-12 16:22:20 +00:00
|
|
|
return unless i2c_smbus_read_byte_data($file, 0x3E) == 0x01
|
|
|
|
and i2c_smbus_read_byte_data($file, 0x3F) == 0x73;
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
|
2004-03-13 18:29:26 +00:00
|
|
|
# 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;
|
2008-05-22 12:01:33 +00:00
|
|
|
|
2004-03-13 18:29:26 +00:00
|
|
|
return
|
|
|
|
unless i2c_smbus_read_byte_data($file, 0x48) == $addr;
|
2008-05-22 12:01:33 +00:00
|
|
|
|
2004-03-13 18:29:26 +00:00
|
|
|
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;
|
|
|
|
|
2008-11-24 17:28:25 +00:00
|
|
|
return 7;
|
2004-03-13 18:29:26 +00:00
|
|
|
}
|
|
|
|
|
2005-04-13 20:06:40 +00:00
|
|
|
# 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);
|
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# Chip to detect: 1 = DME1737, 2 = SCH5027
|
2006-09-26 09:18:33 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x3E: Manufacturer ID
|
|
|
|
# 0x3F: Version/Stepping
|
2007-04-03 12:55:30 +00:00
|
|
|
# 0x73: Read-only test register (4 test bits)
|
|
|
|
# 0x8A: Read-only test register (7 test bits)
|
2008-02-03 21:03:07 +00:00
|
|
|
# 0xBA: Read-only test register (8 test bits)
|
2006-09-26 09:18:33 +00:00
|
|
|
sub dme1737_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2008-02-03 21:03:07 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-09-26 09:18:33 +00:00
|
|
|
return ($addr == 0x2e ? 6 : 5);
|
|
|
|
}
|
|
|
|
|
2008-11-24 16:51:00 +00:00
|
|
|
# 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
|
2006-04-01 11:43:55 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x5A-0x5B: Chip ID
|
|
|
|
# 0x5D-0x5E: Vendor ID
|
|
|
|
sub fintek_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2006-04-01 11:43:55 +00:00
|
|
|
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;
|
2006-04-04 17:13:32 +00:00
|
|
|
} elsif ($chip == 3) { # F75373S/SG
|
|
|
|
return unless $chipid == 0x0204;
|
|
|
|
} elsif ($chip == 4) { # F75375S/SP
|
2006-04-01 11:43:55 +00:00
|
|
|
return unless $chipid == 0x0306;
|
|
|
|
} elsif ($chip == 5) { # F75387SG/RG
|
|
|
|
return unless $chipid == 0x0410;
|
2006-04-04 17:13:32 +00:00
|
|
|
} 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;
|
2006-04-01 11:43:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 7;
|
|
|
|
}
|
|
|
|
|
2004-03-21 16:40:46 +00:00
|
|
|
# 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.
|
2002-10-13 15:48:34 +00:00
|
|
|
sub smartbatt_detect
|
|
|
|
{
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($file, $addr) = @_;
|
2008-11-24 17:26:33 +00:00
|
|
|
|
|
|
|
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;
|
2008-11-24 17:28:25 +00:00
|
|
|
return 5;
|
2002-10-13 15:48:34 +00:00
|
|
|
}
|
|
|
|
|
2008-11-24 17:24:32 +00:00
|
|
|
# Chip to detect: 0 = W83L784R/AR/G, 1 = W83L785R/G, 2 = W83L786NR/NG/R/G,
|
|
|
|
# 3 = W83L785TS-S
|
2003-07-26 09:37:12 +00:00
|
|
|
# Registers used:
|
2004-02-21 13:51:57 +00:00
|
|
|
# 0x40: Configuration
|
2007-08-12 19:41:33 +00:00
|
|
|
# 0x4a: Full I2C Address (W83L784R only)
|
|
|
|
# 0x4b: I2C addresses of emulated LM75 chips (W83L784R only)
|
2003-07-26 09:37:12 +00:00
|
|
|
# 0x4c: Winbond Vendor ID (Low Byte)
|
|
|
|
# 0x4d: Winbond Vendor ID (High Byte)
|
|
|
|
# 0x4e: Chip ID
|
|
|
|
sub w83l784r_detect
|
|
|
|
{
|
2008-11-24 16:51:00 +00:00
|
|
|
my ($file, $addr, $chip) = @_;
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($reg, @res);
|
2003-07-26 09:37:12 +00:00
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
return unless (i2c_smbus_read_byte_data($file, 0x40) & 0x80) == 0x00;
|
2004-02-21 13:51:57 +00:00
|
|
|
return if $chip == 0
|
2008-05-22 12:01:33 +00:00
|
|
|
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;
|
2003-07-26 09:37:12 +00:00
|
|
|
|
2007-08-12 19:41:33 +00:00
|
|
|
$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;
|
2008-11-24 17:24:32 +00:00
|
|
|
return if $chip == 3 and $reg != 0x70;
|
2004-02-21 13:51:57 +00:00
|
|
|
|
2008-11-24 17:24:32 +00:00
|
|
|
return 8 if $chip != 0; # No subclients
|
2008-05-22 12:01:33 +00:00
|
|
|
|
2003-07-26 09:37:12 +00:00
|
|
|
@res = (8);
|
2007-08-12 19:41:33 +00:00
|
|
|
$reg = i2c_smbus_read_byte_data($file, 0x4b);
|
2008-05-22 12:01:33 +00:00
|
|
|
push @res, ($reg & 0x07) + 0x48 unless $reg & 0x08;
|
2003-07-26 09:37:12 +00:00
|
|
|
push @res, (($reg & 0x70) >> 4) + 0x48 unless $reg & 0x80;
|
|
|
|
return @res;
|
|
|
|
}
|
|
|
|
|
2003-08-31 20:45:12 +00:00
|
|
|
# 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.
|
|
|
|
#
|
2008-05-22 12:01:33 +00:00
|
|
|
# The always zero bits are:
|
|
|
|
# configuration byte register (0x02) - top 2 bits
|
2003-08-31 20:45:12 +00:00
|
|
|
# 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
|
2004-05-26 19:04:44 +00:00
|
|
|
# Additionally, not all values are possible for lower 3 bits of
|
|
|
|
# the configuration register.
|
2003-08-31 20:45:12 +00:00
|
|
|
sub max6650_detect
|
|
|
|
{
|
2008-11-24 15:27:26 +00:00
|
|
|
my ($file, $addr) = @_;
|
2004-05-26 19:04:44 +00:00
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
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;
|
2004-05-26 19:04:44 +00:00
|
|
|
return if ($conf & 0xC0) or ($conf & 0x07) > 4;
|
|
|
|
|
2008-01-06 14:14:25 +00:00
|
|
|
return 3;
|
2003-08-31 20:45:12 +00:00
|
|
|
}
|
2001-12-31 17:32:54 +00:00
|
|
|
|
2007-04-03 12:55:30 +00:00
|
|
|
sub max6655_detect
|
|
|
|
{
|
2008-11-24 15:27:26 +00:00
|
|
|
my ($file, $addr) = @_;
|
2007-04-03 12:55:30 +00:00
|
|
|
|
|
|
|
# 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;
|
|
|
|
}
|
|
|
|
|
2005-02-13 16:56:42 +00:00
|
|
|
# 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
|
|
|
|
{
|
2008-11-24 15:27:26 +00:00
|
|
|
my ($file, $addr) = @_;
|
2008-05-22 12:01:33 +00:00
|
|
|
return unless (i2c_smbus_read_byte_data($file, 0x48) & 0x7f) == $addr;
|
|
|
|
return unless i2c_smbus_read_byte_data($file, 0x3f) == 0xb0;
|
2005-02-13 16:56:42 +00:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2008-11-24 15:42:03 +00:00
|
|
|
# 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 unless ($chip == 0 and ($reg == 0x00 or $reg == 0x20 or $reg == 0x40)) or
|
|
|
|
($chip == 2 and ($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 and ($reg1 & 0xfe) != 0x10;
|
|
|
|
return if $chip == 1 and ($reg1 & 0xfe) != 0x30;
|
|
|
|
|
|
|
|
return 8;
|
|
|
|
}
|
|
|
|
|
2008-11-24 15:50:00 +00:00
|
|
|
# We simply look for a register at standard locations.
|
2008-11-24 15:42:03 +00:00
|
|
|
# For KCS, use the STATUS register. For SMIC, use the FLAGS register.
|
2008-11-24 15:50:00 +00:00
|
|
|
# Incidentally they live at the same offset.
|
|
|
|
sub ipmi_detect
|
2008-11-24 15:42:03 +00:00
|
|
|
{
|
2008-11-24 15:50:00 +00:00
|
|
|
my ($addr) = @_;
|
|
|
|
return if inb($addr + 3) == 0xff;
|
2008-11-24 15:42:03 +00:00
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
2008-11-24 14:51:11 +00:00
|
|
|
###################
|
|
|
|
# ALIAS DETECTION #
|
|
|
|
###################
|
|
|
|
|
|
|
|
# These functions take at least 3 parameters:
|
|
|
|
# $_[0]: ISA/LPC address
|
2008-06-07 21:14:07 +00:00
|
|
|
# $_[1]: I2C file handle
|
|
|
|
# $_[2]: I2C address
|
2008-11-24 14:51:11 +00:00
|
|
|
# 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;
|
|
|
|
}
|
|
|
|
|
2005-02-13 16:56:42 +00:00
|
|
|
sub vt1211_alias_detect
|
|
|
|
{
|
2008-06-07 21:14:07 +00:00
|
|
|
my ($isa_addr, $file, $i2c_addr) = @_;
|
2005-02-13 16:56:42 +00:00
|
|
|
my $i;
|
2008-11-24 14:51:11 +00:00
|
|
|
|
2005-02-13 16:56:42 +00:00
|
|
|
return 0 unless (inb($isa_addr + 0x48) & 0x7f) == $i2c_addr;
|
2008-06-07 21:14:07 +00:00
|
|
|
for ($i = 0x2b; $i <= 0x3d; $i++) {
|
2008-05-22 12:01:33 +00:00
|
|
|
return 0 unless inb($isa_addr + $i) == i2c_smbus_read_byte_data($file, $i);
|
2005-02-13 16:56:42 +00:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-08-23 18:52:46 +00:00
|
|
|
|
|
|
|
######################
|
|
|
|
# PCI CHIP DETECTION #
|
|
|
|
######################
|
|
|
|
|
2008-11-22 15:52:52 +00:00
|
|
|
# Returns: undef if not detected, (9) if detected.
|
2006-08-23 18:52:46 +00:00
|
|
|
# The address is encoded in PCI space. We could decode it and print it.
|
|
|
|
sub sis5595_pci_detect
|
|
|
|
{
|
|
|
|
return unless exists $pci_list{'1039:0008'};
|
2008-11-22 15:52:52 +00:00
|
|
|
return 9;
|
2006-08-23 18:52:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Returns: undef if not detected, (9) if detected.
|
|
|
|
# The address is encoded in PCI space. We could decode it and print it.
|
|
|
|
sub via686a_pci_detect
|
|
|
|
{
|
|
|
|
return unless exists $pci_list{'1106:3057'};
|
|
|
|
return 9;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Returns: undef if not detected, (9) if detected.
|
|
|
|
# The address is encoded in PCI space. We could decode it and print it.
|
|
|
|
sub via8231_pci_detect
|
|
|
|
{
|
|
|
|
return unless exists $pci_list{'1106:8235'};
|
|
|
|
return 9;
|
|
|
|
}
|
|
|
|
|
2006-08-23 18:14:09 +00:00
|
|
|
# Returns: undef if not detected, (9) if detected.
|
|
|
|
sub k8temp_pci_detect
|
|
|
|
{
|
|
|
|
return unless exists $pci_list{'1022:1103'};
|
|
|
|
return 9;
|
|
|
|
}
|
|
|
|
|
2007-10-07 18:31:16 +00:00
|
|
|
sub k10temp_pci_detect
|
|
|
|
{
|
|
|
|
return unless exists $pci_list{'1022:1203'};
|
|
|
|
return 9;
|
|
|
|
}
|
|
|
|
|
2006-12-10 20:55:06 +00:00
|
|
|
# Returns: undef if not detected, (9) if detected.
|
|
|
|
sub intel_amb_detect
|
|
|
|
{
|
2008-10-22 12:50:32 +00:00
|
|
|
if ((exists $pci_list{'8086:25f0'}) || # Intel 5000
|
|
|
|
(exists $pci_list{'8086:4030'})) { # Intel 5400
|
2006-12-26 11:53:20 +00:00
|
|
|
return 9;
|
|
|
|
}
|
|
|
|
return;
|
2006-12-10 20:55:06 +00:00
|
|
|
}
|
|
|
|
|
2006-10-15 19:26:10 +00:00
|
|
|
# Returns: undef if not detected, (9) if detected.
|
|
|
|
sub coretemp_detect
|
|
|
|
{
|
|
|
|
my $probecpu;
|
|
|
|
foreach $probecpu (@cpu) {
|
2008-11-27 21:46:01 +00:00
|
|
|
if ($probecpu->{vendor_id} eq 'GenuineIntel' &&
|
2008-11-28 08:07:19 +00:00
|
|
|
$probecpu->{'cpu family'} == 6 &&
|
2008-11-27 21:46:01 +00:00
|
|
|
($probecpu->{model} == 14 ||
|
|
|
|
$probecpu->{model} == 15 ||
|
|
|
|
$probecpu->{model} == 0x16 ||
|
|
|
|
$probecpu->{model} == 0x17)) {
|
2006-10-15 19:26:10 +00:00
|
|
|
return 9;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2001-11-19 20:29:27 +00:00
|
|
|
|
2008-06-24 06:29:19 +00:00
|
|
|
# Returns: undef if not detected, (9) if detected.
|
|
|
|
sub c7temp_detect
|
|
|
|
{
|
|
|
|
my $probecpu;
|
|
|
|
foreach $probecpu (@cpu) {
|
2008-11-27 21:46:01 +00:00
|
|
|
if ($probecpu->{vendor_id} eq 'CentaurHauls' &&
|
2008-11-28 08:07:19 +00:00
|
|
|
$probecpu->{'cpu family'} == 6 &&
|
2008-11-27 21:46:01 +00:00
|
|
|
($probecpu->{model} == 0xa ||
|
|
|
|
$probecpu->{model} == 0xd)) {
|
2008-06-24 06:29:19 +00:00
|
|
|
return 9;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-02-28 17:41:46 +00:00
|
|
|
################
|
|
|
|
# MAIN PROGRAM #
|
|
|
|
################
|
|
|
|
|
|
|
|
# $_[0]: reference to a list of chip hashes
|
2008-05-22 12:01:33 +00:00
|
|
|
sub print_chips_report
|
1999-02-28 17:41:46 +00:00
|
|
|
{
|
|
|
|
my ($listref) = @_;
|
|
|
|
my $data;
|
2008-05-22 12:01:33 +00:00
|
|
|
|
1999-02-28 17:41:46 +00:00
|
|
|
foreach $data (@$listref) {
|
|
|
|
my $is_i2c = exists $data->{i2c_addr};
|
|
|
|
my $is_isa = exists $data->{isa_addr};
|
|
|
|
print " * ";
|
|
|
|
if ($is_i2c) {
|
2005-09-10 14:39:55 +00:00
|
|
|
printf "Bus `%s'\n", $data->{i2c_adap};
|
2008-05-22 12:01:33 +00:00
|
|
|
printf " Busdriver `%s', I2C address 0x%02x",
|
1999-02-28 17:41:46 +00:00
|
|
|
$data->{i2c_driver}, $data->{i2c_addr};
|
|
|
|
if (exists $data->{i2c_sub_addrs}) {
|
|
|
|
print " (and";
|
|
|
|
my $sub_addr;
|
|
|
|
foreach $sub_addr (@{$data->{i2c_sub_addrs}}) {
|
2008-05-22 12:01:33 +00:00
|
|
|
printf " 0x%02x", $sub_addr;
|
1999-02-28 17:41:46 +00:00
|
|
|
}
|
|
|
|
print ")"
|
|
|
|
}
|
2006-10-15 09:30:45 +00:00
|
|
|
print "\n ";
|
1999-02-28 17:41:46 +00:00
|
|
|
}
|
|
|
|
if ($is_isa) {
|
2006-10-15 09:30:45 +00:00
|
|
|
print "ISA bus";
|
1999-02-28 17:41:46 +00:00
|
|
|
if ($data->{isa_addr}) {
|
2006-10-15 09:30:45 +00:00
|
|
|
printf ", address 0x%x", $data->{isa_addr};
|
1999-02-28 17:41:46 +00:00
|
|
|
}
|
2006-10-15 09:30:45 +00:00
|
|
|
print " (Busdriver `i2c-isa')"
|
|
|
|
unless kernel_version_at_least(2, 6, 18);
|
|
|
|
print "\n ";
|
1999-02-28 17:41:46 +00:00
|
|
|
}
|
2006-10-15 09:30:45 +00:00
|
|
|
printf "Chip `%s' (confidence: %d)\n",
|
1999-02-28 17:41:46 +00:00
|
|
|
$data->{chipname}, $data->{conf};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-03-09 16:19:30 +00:00
|
|
|
sub generate_modprobes
|
1999-02-28 16:17:49 +00:00
|
|
|
{
|
2008-11-27 17:47:07 +00:00
|
|
|
my ($chip, $detection, @optionlist, $adap);
|
|
|
|
my ($isa, $ipmi);
|
|
|
|
my ($modprobes, $configfile);
|
1999-03-09 16:19:30 +00:00
|
|
|
|
2008-11-27 17:53:36 +00:00
|
|
|
foreach $chip (@chips_detected) {
|
|
|
|
foreach $detection (@{$chip->{detected}}) {
|
|
|
|
# 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}++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (exists $detection->{isa_addr}) {
|
|
|
|
$isa = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($chip->{driver} eq "ipmisensors") {
|
|
|
|
$ipmi = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-27 17:44:12 +00:00
|
|
|
# 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 $chip (@chips_detected) {
|
|
|
|
@optionlist = ();
|
|
|
|
foreach $detection (@{$chip->{detected}}) {
|
|
|
|
if (exists $detection->{i2c_driver} and
|
2008-11-27 17:53:36 +00:00
|
|
|
exists $detection->{isa_addr} and
|
|
|
|
$i2c_adapters[$detection->{i2c_devnr}]->{used}) {
|
2008-11-27 17:44:12 +00:00
|
|
|
push @optionlist, $detection->{i2c_devnr},
|
|
|
|
$detection->{i2c_addr};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
next if not @optionlist;
|
|
|
|
$configfile = "# hwmon module options\n" unless defined $configfile;
|
|
|
|
$configfile .= "options $chip->{driver}";
|
|
|
|
$configfile .= sprintf(" ignore=%d,0x%02x", shift @optionlist,
|
|
|
|
shift @optionlist);
|
|
|
|
$configfile .= sprintf(",%d,0x%02x", shift @optionlist,
|
|
|
|
shift @optionlist) while @optionlist;
|
|
|
|
$configfile .= "\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 unless contains($adap->{driver}, @modules_we_loaded);
|
|
|
|
next if not defined $configfile and not $adap->{used};
|
|
|
|
$modprobes .= "# I2C adapter drivers\n" unless defined $modprobes;
|
|
|
|
$modprobes .= "modprobe $adap->{driver}\n"
|
|
|
|
unless $modprobes =~ /modprobe $adap->{driver}\n/;
|
1999-02-28 17:24:41 +00:00
|
|
|
}
|
2008-11-27 17:44:12 +00:00
|
|
|
|
2006-08-11 07:34:32 +00:00
|
|
|
# i2c-isa is loaded automatically (as a dependency) since 2.6.14,
|
|
|
|
# and will soon be gone.
|
|
|
|
$modprobes .= "modprobe i2c-isa\n" if ($isa && !kernel_version_at_least(2, 6, 18));
|
2007-06-08 14:39:06 +00:00
|
|
|
if ($ipmi) {
|
2005-02-13 23:04:54 +00:00
|
|
|
$modprobes .= "# You must also install and load the IPMI modules\n";
|
2008-11-22 15:52:52 +00:00
|
|
|
$modprobes .= "modprobe ipmi-si\n";
|
2005-02-13 23:04:54 +00:00
|
|
|
}
|
1999-02-28 17:24:41 +00:00
|
|
|
|
1999-03-09 16:19:30 +00:00
|
|
|
# Now determine the chip probe lines
|
2006-08-23 18:19:58 +00:00
|
|
|
$modprobes .= "# Chip drivers\n";
|
1999-03-09 16:19:30 +00:00
|
|
|
foreach $chip (@chips_detected) {
|
|
|
|
next if not @{$chip->{detected}};
|
2003-08-07 13:03:25 +00:00
|
|
|
if ($chip->{driver} eq "to-be-written") {
|
2004-05-12 19:41:37 +00:00
|
|
|
$modprobes .= "# no driver for $chip->{detected}[0]{chipname} yet\n";
|
2006-09-06 15:43:14 +00:00
|
|
|
} else {
|
2008-11-22 15:52:52 +00:00
|
|
|
open(local *INPUTFILE, "modprobe -l $chip->{driver} 2>/dev/null |");
|
2005-02-13 22:33:43 +00:00
|
|
|
local $_;
|
|
|
|
my $modulefound = 0;
|
|
|
|
while (<INPUTFILE>) {
|
2008-05-22 12:01:33 +00:00
|
|
|
if (m@/@) {
|
2005-02-13 22:33:43 +00:00
|
|
|
$modulefound = 1;
|
|
|
|
last;
|
|
|
|
}
|
|
|
|
}
|
2008-05-28 09:32:41 +00:00
|
|
|
close(INPUTFILE);
|
2005-02-13 22:33:43 +00:00
|
|
|
#check return value from modprobe in case modprobe -l isn't supported
|
2008-05-22 12:01:33 +00:00
|
|
|
if ((($? >> 8) == 0) && ! $modulefound) {
|
2006-09-01 20:52:58 +00:00
|
|
|
$modprobes .= "# Warning: the required module $chip->{driver} is not currently installed\n".
|
2006-09-24 10:37:01 +00:00
|
|
|
"# on your system. For status of 2.6 kernel ports check\n".
|
|
|
|
"# http://www.lm-sensors.org/wiki/Devices. If driver is built\n".
|
2006-09-01 20:52:58 +00:00
|
|
|
"# into the kernel, or unavailable, comment out the following line.\n";
|
2005-02-13 22:33:43 +00:00
|
|
|
}
|
|
|
|
$modprobes .= "modprobe $chip->{driver}\n";
|
2003-08-07 13:03:25 +00:00
|
|
|
}
|
1999-03-09 16:19:30 +00:00
|
|
|
}
|
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
return ($modprobes, $configfile);
|
|
|
|
|
1999-03-09 16:19:30 +00:00
|
|
|
}
|
1999-02-17 20:55:23 +00:00
|
|
|
|
1999-02-19 01:52:29 +00:00
|
|
|
sub main
|
|
|
|
{
|
2006-08-28 21:19:59 +00:00
|
|
|
# We won't go very far if not root
|
|
|
|
unless ($> == 0) {
|
|
|
|
print "You need to be root to run this script.\n";
|
|
|
|
exit -1;
|
|
|
|
}
|
|
|
|
|
2008-03-12 20:50:19 +00:00
|
|
|
if (-x "/sbin/service" && -f "/etc/init.d/lm_sensors" &&
|
|
|
|
-f "/var/lock/subsys/lm_sensors") {
|
|
|
|
system("/sbin/service", "lm_sensors", "stop");
|
|
|
|
}
|
|
|
|
|
2007-07-07 20:04:59 +00:00
|
|
|
initialize_kernel_version();
|
2008-05-28 09:32:41 +00:00
|
|
|
initialize_conf();
|
2008-11-22 15:52:52 +00:00
|
|
|
initialize_pci();
|
2008-05-28 09:32:41 +00:00
|
|
|
initialize_modules_list();
|
2008-02-26 13:50:33 +00:00
|
|
|
# make sure any special case chips are added to the chip_ids list before
|
|
|
|
# making the support modules list
|
|
|
|
chip_special_cases();
|
2008-05-28 09:32:41 +00:00
|
|
|
initialize_modules_supported();
|
2006-10-15 08:46:36 +00:00
|
|
|
initialize_cpu_list();
|
1999-02-19 01:52:29 +00:00
|
|
|
|
2006-08-29 09:17:56 +00:00
|
|
|
print "# sensors-detect revision $revision\n\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";
|
|
|
|
print "\n";
|
|
|
|
|
2008-11-26 16:36:04 +00:00
|
|
|
adapter_pci_detection();
|
1999-02-19 01:52:29 +00:00
|
|
|
print "\n";
|
|
|
|
|
2008-02-21 08:21:20 +00:00
|
|
|
print "If you have undetectable or unsupported I2C/SMBus adapters, you can have\n".
|
|
|
|
"them scanned by manually loading the modules before running this script.\n\n";
|
2007-06-26 07:47:30 +00:00
|
|
|
initialize_i2c_adapters_list();
|
1999-02-19 01:52:29 +00:00
|
|
|
|
2008-11-26 16:36:04 +00:00
|
|
|
load_module("i2c-dev") unless -e "$sysfs_root/class/i2c-dev";
|
1999-02-19 01:52:29 +00:00
|
|
|
|
2007-04-03 12:55:30 +00:00
|
|
|
$i2c_addresses_to_scan = i2c_addresses_to_scan();
|
2006-06-18 16:53:02 +00:00
|
|
|
|
2006-08-29 09:17:56 +00:00
|
|
|
print "We are now going to do the I2C/SMBus adapter probings. Some chips may\n",
|
2006-09-01 16:45:50 +00:00
|
|
|
"be double detected; we choose the one with the highest confidence\n",
|
|
|
|
"value in that case.\n",
|
|
|
|
"If you found that the adapter hung after probing a certain address,\n",
|
|
|
|
"you can specify that address to remain unprobed.\n";
|
1999-02-19 01:52:29 +00:00
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($inp, @not_to_scan, $inp2);
|
2007-06-26 07:47:30 +00:00
|
|
|
for (my $dev_nr = 0; $dev_nr < @i2c_adapters; $dev_nr++) {
|
|
|
|
next unless exists $i2c_adapters[$dev_nr];
|
2008-11-27 21:46:01 +00:00
|
|
|
my $adap = $i2c_adapters[$dev_nr]->{name};
|
1999-02-19 01:52:29 +00:00
|
|
|
print "\n";
|
2006-11-14 13:00:36 +00:00
|
|
|
print "Next adapter: $adap (i2c-$dev_nr)\n";
|
1999-02-24 00:22:52 +00:00
|
|
|
print "Do you want to scan it? (YES/no/selectively): ";
|
2008-05-22 12:01:33 +00:00
|
|
|
|
1999-02-24 00:22:52 +00:00
|
|
|
$inp = <STDIN>;
|
|
|
|
if ($inp =~ /^\s*[Ss]/) {
|
|
|
|
print "Please enter one or more addresses not to scan. Separate them ",
|
|
|
|
"with comma's.\n",
|
|
|
|
"You can specify a range by using dashes. Addresses may be ",
|
|
|
|
"decimal (like 54)\n",
|
|
|
|
"or hexadecimal (like 0x33).\n",
|
|
|
|
"Addresses: ";
|
|
|
|
$inp2 = <STDIN>;
|
2008-05-28 09:32:41 +00:00
|
|
|
chop($inp2);
|
2008-05-09 17:59:51 +00:00
|
|
|
@not_to_scan = parse_not_to_scan(0x03, 0x77, $inp2);
|
1999-02-24 00:22:52 +00:00
|
|
|
}
|
2008-11-27 21:46:01 +00:00
|
|
|
scan_adapter($dev_nr, $adap, $i2c_adapters[$dev_nr]->{driver},
|
2008-05-28 09:32:41 +00:00
|
|
|
\@not_to_scan) unless $inp =~ /^\s*[Nn]/;
|
1999-02-19 18:11:03 +00:00
|
|
|
}
|
2006-08-29 09:17:56 +00:00
|
|
|
print "\n";
|
1999-02-19 18:11:03 +00:00
|
|
|
|
2008-02-20 19:05:00 +00:00
|
|
|
# Skip "random" I/O port probing on PPC
|
|
|
|
if ($kernel_arch ne 'ppc'
|
|
|
|
&& $kernel_arch ne 'ppc64') {
|
|
|
|
print "Some chips are also accessible through the ISA I/O ports. We have to\n".
|
|
|
|
"write to arbitrary I/O ports to probe them. This is usually safe though.\n".
|
|
|
|
"Yes, you do have ISA I/O ports even if you do not have any ISA slots!\n";
|
|
|
|
print "Do you want to scan the ISA I/O ports? (YES/no): ";
|
|
|
|
unless (<STDIN> =~ /^\s*n/i) {
|
|
|
|
initialize_ioports();
|
|
|
|
scan_isa_bus();
|
|
|
|
close_ioports();
|
|
|
|
}
|
|
|
|
print "\n";
|
1999-02-23 14:14:32 +00:00
|
|
|
|
2008-02-20 19:05:00 +00:00
|
|
|
print "Some Super I/O chips may also contain sensors. We have to write to\n".
|
|
|
|
"standard I/O ports to probe them. This is usually safe.\n";
|
|
|
|
print "Do you want to scan for Super I/O sensors? (YES/no): ";
|
|
|
|
unless (<STDIN> =~ /^\s*n/i) {
|
|
|
|
initialize_ioports();
|
|
|
|
scan_superio(0x2e, 0x2f);
|
|
|
|
scan_superio(0x4e, 0x4f);
|
|
|
|
close_ioports();
|
|
|
|
}
|
|
|
|
print "\n";
|
2002-12-09 03:01:23 +00:00
|
|
|
}
|
|
|
|
|
2008-02-21 08:21:20 +00:00
|
|
|
print "Some south bridges, CPUs or memory controllers may also contain\n";
|
2008-02-20 19:31:34 +00:00
|
|
|
print "embedded sensors. Do you want to scan for them? (YES/no): ";
|
2006-10-15 09:30:45 +00:00
|
|
|
unless (<STDIN> =~ /^\s*n/i) {
|
2007-04-03 12:55:30 +00:00
|
|
|
$| = 1;
|
2006-10-15 09:30:45 +00:00
|
|
|
foreach my $entry (@cpu_ids) {
|
|
|
|
scan_cpu($entry);
|
|
|
|
}
|
2007-04-03 12:55:30 +00:00
|
|
|
$| = 0;
|
2006-10-15 09:30:45 +00:00
|
|
|
}
|
|
|
|
print "\n";
|
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
if (! @chips_detected) {
|
2006-08-29 09:17:56 +00:00
|
|
|
print "Sorry, no sensors were detected.\n",
|
|
|
|
"Either your sensors are not supported, or they are connected to an\n",
|
2008-04-17 11:39:07 +00:00
|
|
|
"I2C or SMBus adapter that is not supported. See\n",
|
|
|
|
"http://www.lm-sensors.org/wiki/FAQ/Chapter3 for further information.\n",
|
2006-09-24 09:12:42 +00:00
|
|
|
"If you find out what chips are on your board, check\n",
|
2006-09-24 10:37:01 +00:00
|
|
|
"http://www.lm-sensors.org/wiki/Devices for driver status.\n";
|
2002-11-21 23:43:05 +00:00
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
2006-08-29 09:17:56 +00:00
|
|
|
print "Now follows a summary of the probes I have just done.\n".
|
|
|
|
"Just press ENTER to continue: ";
|
1999-03-09 18:11:26 +00:00
|
|
|
<STDIN>;
|
|
|
|
|
2008-05-22 12:01:33 +00:00
|
|
|
my ($chip, $data);
|
1999-02-19 18:11:03 +00:00
|
|
|
foreach $chip (@chips_detected) {
|
2008-11-27 16:00:04 +00:00
|
|
|
next unless @{$chip->{detected}};
|
|
|
|
print "\nDriver `$chip->{driver}':\n";
|
|
|
|
print_chips_report($chip->{detected});
|
1999-02-19 01:52:29 +00:00
|
|
|
}
|
2006-08-29 09:17:56 +00:00
|
|
|
print "\n";
|
1999-03-09 16:19:30 +00:00
|
|
|
|
2008-05-02 11:57:03 +00:00
|
|
|
my ($modprobes, $configfile) = generate_modprobes();
|
2007-12-18 13:04:03 +00:00
|
|
|
|
2007-09-05 16:45:19 +00:00
|
|
|
if (defined $configfile) {
|
2007-12-18 13:04:03 +00:00
|
|
|
my $have_modprobe_d = -d '/etc/modprobe.d';
|
|
|
|
printf "Do you want to \%s /etc/modprobe.d/lm_sensors? (\%s): ",
|
|
|
|
(-e '/etc/modprobe.d/lm_sensors' ? 'overwrite' : 'generate'),
|
|
|
|
($have_modprobe_d ? 'YES/no' : 'yes/NO');
|
|
|
|
$_ = <STDIN>;
|
|
|
|
if (($have_modprobe_d and not m/^\s*n/i) or m/^\s*y/i) {
|
|
|
|
unless ($have_modprobe_d) {
|
2008-05-28 09:32:41 +00:00
|
|
|
mkdir('/etc/modprobe.d', 0777)
|
2007-12-18 13:04:03 +00:00
|
|
|
or die "Sorry, can't create /etc/modprobe.d ($!)";
|
|
|
|
}
|
|
|
|
open(local *MODPROBE_D, ">/etc/modprobe.d/lm_sensors")
|
|
|
|
or die "Sorry, can't create /etc/modprobe.d/lm_sensors ($!)";
|
|
|
|
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".
|
2008-11-22 15:52:52 +00:00
|
|
|
"/etc/modprobe.conf:\n\n";
|
2007-12-18 13:04:03 +00:00
|
|
|
print "#----cut here----\n".
|
|
|
|
$configfile.
|
|
|
|
"#----cut here----\n\n";
|
|
|
|
}
|
2007-09-05 16:45:19 +00:00
|
|
|
}
|
2006-08-29 09:17:56 +00:00
|
|
|
|
2002-10-17 17:42:00 +00:00
|
|
|
my $have_sysconfig = -d '/etc/sysconfig';
|
2006-09-02 14:00:36 +00:00
|
|
|
printf "Do you want to \%s /etc/sysconfig/lm_sensors? (\%s): ",
|
|
|
|
(-e '/etc/sysconfig/lm_sensors' ? 'overwrite' : 'generate'),
|
|
|
|
($have_sysconfig ? 'YES/no' : 'yes/NO');
|
2006-08-28 21:19:59 +00:00
|
|
|
$_ = <STDIN>;
|
|
|
|
if (($have_sysconfig and not m/^\s*n/i) or m/^\s*y/i) {
|
|
|
|
unless ($have_sysconfig) {
|
2008-05-28 09:32:41 +00:00
|
|
|
mkdir('/etc/sysconfig', 0777)
|
2006-08-28 21:19:59 +00:00
|
|
|
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 <<'EOT';
|
2006-09-01 21:03:41 +00:00
|
|
|
# /etc/sysconfig/lm_sensors - Defines modules loaded by
|
|
|
|
# /etc/init.d/lm_sensors
|
2002-06-30 23:57:34 +00:00
|
|
|
# Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>
|
|
|
|
#
|
|
|
|
# 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
|
2008-03-26 13:37:12 +00:00
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
# MA 02110-1301 USA.
|
2002-06-30 23:57:34 +00:00
|
|
|
#
|
|
|
|
#
|
|
|
|
# See also the lm_sensors homepage at:
|
2006-09-01 21:03:41 +00:00
|
|
|
# http://www.lm-sensors.org/
|
2002-06-30 23:57:34 +00:00
|
|
|
#
|
2006-09-01 21:03:41 +00:00
|
|
|
# This file is used by /etc/init.d/lm_sensors and defines the modules to
|
|
|
|
# be loaded/unloaded. This file is sourced into /etc/init.d/lm_sensors.
|
2002-06-30 23:57:34 +00:00
|
|
|
#
|
|
|
|
# The format of this file is a shell script that simply defines the modules
|
|
|
|
# in order as normal variables with the special names:
|
2002-09-28 20:42:02 +00:00
|
|
|
# MODULE_0, MODULE_1, MODULE_2, etc.
|
2002-06-30 23:57:34 +00:00
|
|
|
#
|
|
|
|
# List the modules that are to be loaded for your system
|
|
|
|
#
|
|
|
|
EOT
|
2006-08-28 21:19:59 +00:00
|
|
|
print SYSCONFIG
|
|
|
|
"# Generated by sensors-detect on " . scalar localtime() . "\n";
|
|
|
|
my @modules = grep /^modprobe /, split "\n", $modprobes;
|
|
|
|
my $i = 0;
|
|
|
|
my $sysconfig = "";
|
|
|
|
foreach (@modules) {
|
|
|
|
s/^modprobe //;
|
|
|
|
$sysconfig .= "MODULE_$i=$_\n";
|
|
|
|
$i++;
|
2002-06-30 23:57:34 +00:00
|
|
|
}
|
2006-08-28 21:19:59 +00:00
|
|
|
print SYSCONFIG $sysconfig;
|
2007-12-18 13:04:03 +00:00
|
|
|
close(SYSCONFIG);
|
2006-09-01 21:03:41 +00:00
|
|
|
|
|
|
|
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";
|
2007-12-18 13:04:03 +00:00
|
|
|
|
2007-12-19 22:36:13 +00:00
|
|
|
if (-x "/sbin/insserv" && -f "/etc/init.d/lm_sensors") {
|
|
|
|
system("/sbin/insserv", "/etc/init.d/lm_sensors");
|
2008-03-12 20:50:19 +00:00
|
|
|
} 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");
|
|
|
|
}
|
2007-12-19 22:36:13 +00:00
|
|
|
} else {
|
|
|
|
print "You should now start the lm_sensors service to load the required\n".
|
|
|
|
"kernel modules.\n\n";
|
|
|
|
}
|
2007-12-18 13:04:03 +00:00
|
|
|
} else {
|
2007-12-19 22:36:13 +00:00
|
|
|
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";
|
2007-12-18 13:04:03 +00:00
|
|
|
print "#----cut here----\n".
|
|
|
|
$modprobes.
|
|
|
|
(-e '/usr/bin/sensors' ?
|
2007-12-19 22:36:13 +00:00
|
|
|
"/usr/bin/sensors -s\n" :
|
|
|
|
"/usr/local/bin/sensors -s\n") .
|
2007-12-18 13:04:03 +00:00
|
|
|
"#----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";
|
2002-06-30 23:57:34 +00:00
|
|
|
}
|
2008-11-26 14:52:07 +00:00
|
|
|
|
|
|
|
unload_modules();
|
1999-02-19 01:52:29 +00:00
|
|
|
}
|
|
|
|
|
2008-11-26 14:52:07 +00:00
|
|
|
sub cleanup_on_int
|
|
|
|
{
|
|
|
|
print "\n";
|
|
|
|
unload_modules();
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
$SIG{INT} = \&cleanup_on_int;
|
|
|
|
|
1999-02-19 01:52:29 +00:00
|
|
|
main;
|