1999-02-06 01:04:57 +00:00
|
|
|
#!/usr/bin/perl
|
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
#
|
|
|
|
# detect.pl - Detect PCI bus and chips
|
|
|
|
# Copyright (c) 1998, 1999 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
|
|
|
|
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
#
|
|
|
|
|
1999-02-25 12:23:04 +00:00
|
|
|
# TODO: Better handling of chips with several addresses
|
1999-02-17 20:55:23 +00:00
|
|
|
|
|
|
|
# A Perl wizard really ought to look upon this; the PCI and I2C stuff should
|
|
|
|
# each be put in a separate file, using modules and packages. That is beyond
|
|
|
|
# me.
|
|
|
|
|
1999-03-10 01:17:15 +00:00
|
|
|
require 5.004;
|
|
|
|
|
1999-02-06 01:04:57 +00:00
|
|
|
use strict;
|
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
#########################
|
|
|
|
# CONSTANT DECLARATIONS #
|
|
|
|
#########################
|
|
|
|
|
1999-02-19 01:52:29 +00:00
|
|
|
use vars qw(@pci_adapters @chip_ids @undetectable_adapters);
|
|
|
|
|
|
|
|
@undetectable_adapters = ( "bit-lp", "bit-velle" );
|
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.
|
|
|
|
# Each entry must have a vindid (Vendor ID), devid (Device ID), func (PCI
|
|
|
|
# Function) and procid (string as appears in /proc/pci; see linux/driver/pci,
|
|
|
|
# either pci.c or oldproc.c). If no driver is written yet, omit the
|
1999-02-19 18:11:03 +00:00
|
|
|
# driver (Driver Name) field. The match (Match Description) field should
|
1999-02-23 14:14:32 +00:00
|
|
|
# contain a function which returns zero if its two parameter matches
|
1999-02-19 18:11:03 +00:00
|
|
|
# the text as it would appear in /proc/bus/i2c.
|
1999-02-17 20:55:23 +00:00
|
|
|
@pci_adapters = (
|
|
|
|
{
|
|
|
|
vendid => 0x8086,
|
|
|
|
devid => 0x7113,
|
|
|
|
func => 3,
|
|
|
|
procid => "Intel 82371AB PIIX4 ACPI",
|
1999-02-19 18:11:03 +00:00
|
|
|
driver => "i2c-piix4",
|
|
|
|
match => sub { $_[0] =~ /^SMBus PIIX4 adapter at [0-9,a-f]{4}/ },
|
1999-02-17 20:55:23 +00:00
|
|
|
} ,
|
|
|
|
{
|
|
|
|
vendid => 0x1106,
|
|
|
|
devid => 0x3040,
|
|
|
|
func => 3,
|
|
|
|
procid => "VIA Technologies VT 82C586B Apollo ACPI",
|
1999-02-19 18:11:03 +00:00
|
|
|
driver => "i2c-via",
|
|
|
|
match => sub { $_[0] =~ /^VIA i2c/ },
|
1999-02-17 20:55:23 +00:00
|
|
|
} ,
|
|
|
|
{
|
|
|
|
vendid => 0x1039,
|
|
|
|
devid => 0x0008,
|
|
|
|
func => 0,
|
|
|
|
procid => "Silicon Integrated Systems 85C503",
|
1999-02-19 18:11:03 +00:00
|
|
|
match => sub { 0 },
|
1999-02-17 20:55:23 +00:00
|
|
|
} ,
|
|
|
|
{
|
|
|
|
vendid => 0x10b9,
|
|
|
|
devid => 0x7101,
|
|
|
|
funcid => 0,
|
|
|
|
procid => "Acer Labs M7101",
|
1999-02-19 18:11:03 +00:00
|
|
|
driver => "i2c-ali15x3",
|
|
|
|
match => sub { $_[0] =~ /^SMBus ALI15X3 adapter at [0-9,a-f]{4}/ },
|
1999-02-17 20:55:23 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
1999-02-23 20:28:05 +00:00
|
|
|
use subs qw(lm78_detect lm78_isa_detect lm78_alias_detect lm75_detect
|
|
|
|
lm80_detect w83781d_detect w83781d_alias_detect
|
1999-02-22 20:40:16 +00:00
|
|
|
w83781d_isa_detect gl518sm_detect gl520sm_detect adm9240_detect
|
1999-02-28 16:17:49 +00:00
|
|
|
adm1021_detect sis5595_isa_detect eeprom_detect);
|
1999-02-17 20:55:23 +00:00
|
|
|
|
1999-02-18 00:19:19 +00:00
|
|
|
# This is a list of all recognized chips.
|
1999-02-22 20:40:16 +00:00
|
|
|
# Each entry must have the following fields:
|
|
|
|
# name: The full chip name
|
|
|
|
# driver (optional): The driver name (without .o extension). Omit if none is
|
|
|
|
# written yet.
|
|
|
|
# i2c_addrs (optional): For I2C chips, the range of valid I2C addresses to
|
|
|
|
# probe.
|
1999-03-23 21:48:41 +00:00
|
|
|
# i2c_driver_addrs (optional): For I2C chips, the range of valid I2C
|
|
|
|
# addresses probed by the kernel driver. Strictly optional.
|
1999-02-22 20:40:16 +00:00
|
|
|
# i2c_detect (optional): For I2C chips, the function to call to detect
|
|
|
|
# this chip. The function should take two parameters: an open file
|
|
|
|
# descriptor to access the bus, and the I2C address to probe.
|
1999-02-23 14:14:32 +00:00
|
|
|
# isa_addrs (optional): For ISA chips, the range of valid port addresses to
|
|
|
|
# probe.
|
1999-03-23 21:48:41 +00:00
|
|
|
# isa_driver_addrs (optional): For ISA chips, the range of valid ISA
|
|
|
|
# addresses probed by the kernel driver. Strictly optional.
|
1999-02-22 20:40:16 +00:00
|
|
|
# isa_detect (optional): For ISA chips, the function to call to detect
|
1999-02-23 14:14:32 +00:00
|
|
|
# this chip. The function should take one parameter: the ISA address
|
|
|
|
# to probe.
|
1999-02-23 20:28:05 +00:00
|
|
|
# alias_detect (optional): For chips which can be both on the ISA and the
|
|
|
|
# I2C bus, a function which detectes whether two entries are the same.
|
|
|
|
# The function should take three parameters: The ISA address, the
|
|
|
|
# I2C bus number, and the I2C address.
|
1999-02-18 00:19:19 +00:00
|
|
|
@chip_ids = (
|
|
|
|
{
|
|
|
|
name => "National Semiconductors LM78",
|
|
|
|
driver => "lm78",
|
1999-02-18 18:09:14 +00:00
|
|
|
i2c_addrs => [0x00..0x7f],
|
1999-03-23 21:48:41 +00:00
|
|
|
i2c_driver_addrs => [0x20..0x2f],
|
1999-02-18 18:09:14 +00:00
|
|
|
i2c_detect => sub { lm78_detect 0, @_},
|
1999-02-23 14:14:32 +00:00
|
|
|
isa_addrs => [0x290],
|
|
|
|
isa_detect => sub { lm78_isa_detect 0, @_ },
|
1999-02-23 20:28:05 +00:00
|
|
|
alias_detect => sub { lm78_alias_detect 0, @_ },
|
1999-02-18 00:19:19 +00:00
|
|
|
} ,
|
|
|
|
{
|
|
|
|
name => "National Semiconductors LM78-J",
|
|
|
|
driver => "lm78",
|
1999-02-18 18:09:14 +00:00
|
|
|
i2c_addrs => [0x00..0x7f],
|
1999-03-23 21:48:41 +00:00
|
|
|
i2c_driver_addrs => [0x20..0x2f],
|
1999-02-18 18:09:14 +00:00
|
|
|
i2c_detect => sub { lm78_detect 1, @_ },
|
1999-02-23 14:14:32 +00:00
|
|
|
isa_addrs => [0x290],
|
|
|
|
isa_detect => sub { lm78_isa_detect 1, @_ },
|
1999-02-23 20:28:05 +00:00
|
|
|
alias_detect => sub { lm78_alias_detect 1, @_ },
|
1999-02-18 00:19:19 +00:00
|
|
|
} ,
|
|
|
|
{
|
|
|
|
name => "National Semiconductors LM79",
|
|
|
|
driver => "lm78",
|
1999-02-18 18:09:14 +00:00
|
|
|
i2c_addrs => [0x00..0x7f],
|
1999-03-23 21:48:41 +00:00
|
|
|
i2c_driver_addrs => [0x20..0x2f],
|
1999-02-18 18:09:14 +00:00
|
|
|
i2c_detect => sub { lm78_detect 2, @_ },
|
1999-02-23 14:14:32 +00:00
|
|
|
isa_addrs => [0x290],
|
|
|
|
isa_detect => sub { lm78_isa_detect 2, @_ },
|
1999-02-23 20:28:05 +00:00
|
|
|
alias_detect => sub { lm78_alias_detect 2, @_ },
|
1999-02-18 00:19:19 +00:00
|
|
|
} ,
|
|
|
|
{
|
|
|
|
name => "National Semiconductors LM75",
|
|
|
|
driver => "lm75",
|
1999-02-18 18:09:14 +00:00
|
|
|
i2c_addrs => [0x48..0x4f],
|
|
|
|
i2c_detect => sub { lm75_detect @_},
|
1999-02-18 00:19:19 +00:00
|
|
|
} ,
|
|
|
|
{
|
|
|
|
name => "National Semiconductors LM80",
|
|
|
|
driver => "lm80",
|
1999-02-18 18:09:14 +00:00
|
|
|
i2c_addrs => [0x28..0x2f],
|
|
|
|
i2c_detect => sub { lm80_detect @_} ,
|
1999-02-18 21:14:48 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name => "Winbond W83781D",
|
|
|
|
driver => "w83781d",
|
|
|
|
i2c_addrs => [0x00..0x7f],
|
|
|
|
i2c_detect => sub { w83781d_detect 0, @_},
|
1999-03-24 21:28:22 +00:00
|
|
|
i2c_driver_addrs => [0x20..0x2f],
|
1999-02-23 14:14:32 +00:00
|
|
|
isa_addrs => [0x290],
|
|
|
|
isa_detect => sub { w83781d_isa_detect 0, @_ },
|
1999-02-23 20:28:05 +00:00
|
|
|
alias_detect => sub { w83781d_alias_detect 0, @_ },
|
1999-02-18 21:14:48 +00:00
|
|
|
} ,
|
1999-02-22 18:20:35 +00:00
|
|
|
{
|
|
|
|
name => "Winbond W83782D",
|
|
|
|
driver => "w83781d",
|
|
|
|
i2c_addrs => [0x00..0x7f],
|
1999-03-24 21:28:22 +00:00
|
|
|
i2c_driver_addrs => [0x20..0x2f],
|
1999-02-22 18:20:35 +00:00
|
|
|
i2c_detect => sub { w83781d_detect 1, @_},
|
|
|
|
} ,
|
|
|
|
{
|
|
|
|
name => "Winbond W83783S",
|
|
|
|
driver => "w83781d",
|
|
|
|
i2c_addrs => [0x00..0x7f],
|
1999-03-24 21:28:22 +00:00
|
|
|
i2c_driver_addrs => [0x20..0x2f],
|
1999-02-22 18:20:35 +00:00
|
|
|
i2c_detect => sub { w83781d_detect 2, @_},
|
1999-02-23 14:14:32 +00:00
|
|
|
isa_addrs => [0x290],
|
|
|
|
isa_detect => sub { w83781d_isa_detect 2, @_ },
|
1999-02-23 20:28:05 +00:00
|
|
|
alias_detect => sub { w83781d_alias_detect 2, @_ },
|
1999-02-22 18:20:35 +00:00
|
|
|
} ,
|
1999-02-18 21:14:48 +00:00
|
|
|
{
|
|
|
|
name => "Genesys Logic GL518SM Revision 0x00",
|
|
|
|
driver => "gl518sm",
|
1999-04-07 18:37:36 +00:00
|
|
|
i2c_addrs => [0x2c, 0x2d],
|
1999-02-18 21:14:48 +00:00
|
|
|
i2c_detect => sub { gl518sm_detect 0, @_} ,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name => "Genesys Logic GL518SM Revision 0x80",
|
|
|
|
driver => "gl518sm",
|
1999-04-07 18:37:36 +00:00
|
|
|
i2c_addrs => [0x2c, 0x2d],
|
1999-02-18 21:14:48 +00:00
|
|
|
i2c_detect => sub { gl518sm_detect 1, @_} ,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name => "Genesys Logic GL520SM",
|
1999-04-07 18:37:36 +00:00
|
|
|
i2c_addrs => [0x2c, 0x2d],
|
1999-02-19 18:11:03 +00:00
|
|
|
i2c_detect => sub { gl520sm_detect @_} ,
|
1999-02-18 21:14:48 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name => "Analog Devices ADM9240",
|
|
|
|
driver => "adm9240",
|
|
|
|
i2c_addrs => [0x2c..0x2f],
|
1999-03-29 00:58:55 +00:00
|
|
|
i2c_detect => sub { adm9240_detect 0, @_ }
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name => "Dallas Semiconductor DS1780",
|
|
|
|
driver => "adm9240",
|
|
|
|
i2c_addrs => [0x2c..0x2f],
|
|
|
|
i2c_detect => sub { adm9240_detect 1, @_ }
|
1999-02-18 21:14:48 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name => "Analog Devices ADM1021",
|
1999-02-20 01:15:00 +00:00
|
|
|
driver => "adm1021",
|
1999-04-07 19:08:47 +00:00
|
|
|
i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
|
1999-02-18 21:14:48 +00:00
|
|
|
i2c_detect => sub { adm1021_detect 0, @_ },
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name => "Maxim MAX1617",
|
1999-02-20 01:15:00 +00:00
|
|
|
driver => "adm1021",
|
1999-04-07 19:08:47 +00:00
|
|
|
i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
|
1999-02-18 21:14:48 +00:00
|
|
|
i2c_detect => sub { adm1021_detect 1, @_ },
|
|
|
|
},
|
1999-02-23 23:16:09 +00:00
|
|
|
{
|
|
|
|
name => "Silicon Integrated Systems SIS5595",
|
|
|
|
driver => "sis5595",
|
1999-02-24 01:12:05 +00:00
|
|
|
isa_addrs => [ 0 ],
|
1999-02-23 23:16:09 +00:00
|
|
|
isa_detect => sub { sis5595_isa_detect @_ },
|
1999-02-28 16:17:49 +00:00
|
|
|
},
|
|
|
|
{
|
1999-02-28 17:37:50 +00:00
|
|
|
name => "Serial EEPROM (PC-100 DIMM)",
|
1999-02-28 16:17:49 +00:00
|
|
|
driver => "eeprom",
|
|
|
|
i2c_addrs => [0x50..0x57],
|
1999-02-28 17:37:50 +00:00
|
|
|
i2c_detect => sub { eeprom_detect @_ },
|
1999-02-23 23:16:09 +00:00
|
|
|
}
|
1999-02-18 00:19:19 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
#######################
|
|
|
|
# AUXILIARY FUNCTIONS #
|
|
|
|
#######################
|
|
|
|
|
|
|
|
sub swap_bytes
|
|
|
|
{
|
1999-02-19 02:30:17 +00:00
|
|
|
return (($_[0] & 0xff00) >> 8) + (($_[0] & 0x00ff) << 8)
|
1999-02-18 00:19:19 +00:00
|
|
|
}
|
|
|
|
|
1999-02-18 18:09:14 +00:00
|
|
|
# $_[0] is the sought value
|
|
|
|
# @_[1..] is the list to seek in
|
|
|
|
# Returns: 0 on failure, 1 if found.
|
|
|
|
sub contains
|
|
|
|
{
|
|
|
|
my $sought = shift;
|
|
|
|
foreach (@_) {
|
|
|
|
return 1 if $sought eq $_;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
1999-02-18 00:19:19 +00:00
|
|
|
|
1999-02-24 00:22:52 +00:00
|
|
|
sub parse_not_to_scan
|
|
|
|
{
|
|
|
|
my ($min,$max,$to_parse) = @_;
|
|
|
|
my @ranges = split /\s*,\s*/, $to_parse;
|
|
|
|
my @res = ();
|
|
|
|
my $range;
|
|
|
|
foreach $range (@ranges) {
|
|
|
|
my ($start,$end) = split /\s*-s*/, $range;
|
|
|
|
$start = oct $start if $start =~ /^0/;
|
|
|
|
if (defined $end) {
|
|
|
|
$end = oct $end if $end =~ /^0/;
|
|
|
|
$start = $min if $start < $min;
|
|
|
|
$end = $max if $end > $max;
|
|
|
|
push @res, ($start+0..$end+0);
|
|
|
|
} else {
|
|
|
|
push @res, $start+0 if $start >= $min and $start <= $max;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sort { $a <=> $b } @res;
|
|
|
|
}
|
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
|
|
|
|
{
|
|
|
|
my ($list1,$list2) = @_;
|
|
|
|
my ($el1,$el2);
|
|
|
|
foreach $el1 (@$list1) {
|
|
|
|
foreach $el2 (@$list2) {
|
|
|
|
return 1 if $el1 == $el2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1999-02-22 18:20:35 +00:00
|
|
|
###################
|
|
|
|
# I/O port access #
|
|
|
|
###################
|
|
|
|
|
1999-02-23 14:14:32 +00:00
|
|
|
sub initialize_ioports
|
1999-02-22 18:20:35 +00:00
|
|
|
{
|
|
|
|
sysopen IOPORTS, "/dev/port", 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: port to read
|
|
|
|
# Returns: -1 on failure, read value on success.
|
|
|
|
sub inb
|
|
|
|
{
|
|
|
|
my ($res,$nrchars);
|
|
|
|
sysseek IOPORTS, $_[0], 0 or return -1;
|
|
|
|
$nrchars = sysread IOPORTS, $res, 1;
|
|
|
|
return -1 if not defined $nrchars or $nrchars != 1;
|
|
|
|
$res = unpack "C",$res ;
|
|
|
|
return $res;
|
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: port to write
|
|
|
|
# $_[1]: value to write
|
|
|
|
# Returns: -1 on failure, 0 on success.
|
|
|
|
sub outb
|
|
|
|
{
|
|
|
|
my $towrite = pack "C", $_[1];
|
|
|
|
sysseek IOPORTS, $_[0], 0 or return -1;
|
|
|
|
my $nrchars = syswrite IOPORTS, $towrite, 1;
|
|
|
|
return -1 if not defined $nrchars or $nrchars != 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
outb $_[0],$_[2];
|
|
|
|
return inb $_[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: Address register
|
|
|
|
# $_[1]: Data register
|
|
|
|
# $_[2]: Register to write
|
|
|
|
# $_[3}: Value to write
|
|
|
|
# Returns: nothing
|
|
|
|
sub isa_write_byte
|
|
|
|
{
|
|
|
|
outb $_[0],$_[2];
|
|
|
|
outb $_[1],$_[3];
|
|
|
|
}
|
|
|
|
|
1999-02-19 01:52:29 +00:00
|
|
|
###########
|
|
|
|
# MODULES #
|
|
|
|
###########
|
|
|
|
|
|
|
|
use vars qw(@modules_list);
|
|
|
|
|
|
|
|
sub initialize_modules_list
|
|
|
|
{
|
|
|
|
open INPUTFILE, "/proc/modules" or die "Can't access /proc/modules!";
|
|
|
|
while (<INPUTFILE>) {
|
|
|
|
push @modules_list, /^(\S*)/ ;
|
|
|
|
}
|
|
|
|
close INPUTFILE;
|
|
|
|
}
|
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
##############
|
|
|
|
# PCI ACCESS #
|
|
|
|
##############
|
|
|
|
|
1999-02-18 00:19:19 +00:00
|
|
|
use vars qw(@pci_list);
|
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
# This function returns a list of hashes. Each hash has some PCI information
|
|
|
|
# (more than we will ever need, probably). The most important
|
1999-02-06 01:04:57 +00:00
|
|
|
# fields are 'bus', 'slot', 'func' (they uniquely identify a PCI device in
|
|
|
|
# a computer) and 'vendid','devid' (they uniquely identify a type of device).
|
|
|
|
# /proc/bus/pci/devices is only available on late 2.1 and 2.2 kernels.
|
|
|
|
sub read_proc_dev_pci
|
|
|
|
{
|
|
|
|
my ($dfn,$vend,@pci_list);
|
|
|
|
open INPUTFILE, "/proc/bus/pci/devices" or return;
|
|
|
|
while (<INPUTFILE>) {
|
|
|
|
my $record = {};
|
|
|
|
($dfn,$vend,$record->{irq},$record->{base_addr0},$record->{base_addr1},
|
|
|
|
$record->{base_addr2},$record->{base_addr3},$record->{base_addr4},
|
|
|
|
$record->{base_addr5},$record->{rom_base_addr}) =
|
|
|
|
map { oct "0x$_" } split;
|
|
|
|
$record->{bus} = $dfn >> 8;
|
|
|
|
$record->{slot} = ($dfn & 0xf8) >> 3;
|
|
|
|
$record->{func} = $dfn & 0x07;
|
|
|
|
$record->{vendid} = $vend >> 16;
|
|
|
|
$record->{devid} = $vend & 0xffff;
|
|
|
|
push @pci_list,$record;
|
|
|
|
}
|
|
|
|
close INPUTFILE or return;
|
1999-02-17 20:55:23 +00:00
|
|
|
return @pci_list;
|
1999-02-06 01:04:57 +00:00
|
|
|
}
|
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
# This function returns a list of hashes. Each hash has some PCI
|
|
|
|
# information. The important fields here are 'bus', 'slot', 'func' (they
|
1999-02-06 01:04:57 +00:00
|
|
|
# uniquely identify a PCI device in a computer) and 'desc' (a functional
|
1999-02-09 22:41:58 +00:00
|
|
|
# description of the PCI device). If this is an 'unknown device', the
|
|
|
|
# vendid and devid fields are set instead.
|
1999-02-06 01:04:57 +00:00
|
|
|
sub read_proc_pci
|
|
|
|
{
|
|
|
|
my @pci_list;
|
|
|
|
open INPUTFILE, "/proc/pci" or return;
|
|
|
|
while (<INPUTFILE>) {
|
|
|
|
my $record = {};
|
|
|
|
if (($record->{bus},$record->{slot},$record->{func}) =
|
|
|
|
/^\s*Bus\s*(\S)+\s*,\s*device\s*(\S+)\s*,\s*function\s*(\S+)\s*:\s*$/) {
|
1999-02-09 22:41:58 +00:00
|
|
|
my $desc = <INPUTFILE>;
|
|
|
|
unless (($desc =~ /Unknown device/) and
|
|
|
|
(($record->{vendid},$record->{devid}) =
|
|
|
|
/^\s*Vendor id=(\S+)\.\s*Device id=(\S+)\.$/)) {
|
|
|
|
$record->{desc} = $desc;
|
|
|
|
}
|
1999-02-06 01:04:57 +00:00
|
|
|
push @pci_list,$record;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close INPUTFILE or return;
|
1999-02-17 20:55:23 +00:00
|
|
|
return @pci_list;
|
1999-02-06 01:04:57 +00:00
|
|
|
}
|
|
|
|
|
1999-02-19 01:52:29 +00:00
|
|
|
sub initialize_proc_pci
|
1999-02-06 01:04:57 +00:00
|
|
|
{
|
1999-02-17 20:55:23 +00:00
|
|
|
@pci_list = read_proc_dev_pci;
|
|
|
|
@pci_list = read_proc_pci if not defined @pci_list;
|
|
|
|
die "Can't access either /proc/bus/pci/ or /proc/pci!"
|
|
|
|
if not defined @pci_list;
|
|
|
|
}
|
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
|
|
|
|
|
|
|
sub all_available_adapters
|
|
|
|
{
|
|
|
|
my @res = ();
|
|
|
|
my ($module,$adapter);
|
|
|
|
MODULES:
|
|
|
|
foreach $module (@modules_list) {
|
|
|
|
foreach $adapter (@pci_adapters) {
|
|
|
|
if (exists $adapter->{driver} and $module eq $adapter->{driver}) {
|
|
|
|
push @res, $module;
|
|
|
|
next MODULES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return @res;
|
|
|
|
}
|
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
sub adapter_pci_detection
|
|
|
|
{
|
|
|
|
my ($device,$try,@res);
|
1999-02-06 01:04:57 +00:00
|
|
|
print "Probing for PCI bus adapters...\n";
|
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
foreach $device (@pci_list) {
|
1999-02-06 01:04:57 +00:00
|
|
|
foreach $try (@pci_adapters) {
|
1999-02-09 22:41:58 +00:00
|
|
|
if ((defined($device->{vendid}) and
|
|
|
|
$try->{vendid} == $device->{vendid} and
|
|
|
|
$try->{devid} == $device->{devid} and
|
|
|
|
$try->{func} == $device->{func}) or
|
|
|
|
(! defined($device->{vendid}) and
|
|
|
|
$device->{desc} =~ /$try->{procid}/ and
|
|
|
|
$try->{func} == $device->{func})) {
|
|
|
|
printf "Use driver `%s' for device %02x:%02x.%x: %s\n",
|
|
|
|
$try->{driver}?$try->{driver}:"<To Be Written>",
|
1999-02-06 01:04:57 +00:00
|
|
|
$device->{bus},$device->{slot},$device->{func},$try->{procid};
|
|
|
|
push @res,$try->{driver};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (! defined @res) {
|
|
|
|
print ("Sorry, no PCI bus adapters found.\n");
|
|
|
|
} else {
|
|
|
|
printf ("Probe succesfully concluded.\n");
|
|
|
|
}
|
|
|
|
return @res;
|
|
|
|
}
|
|
|
|
|
1999-02-23 14:14:32 +00:00
|
|
|
# $_[0]: Adapter description as found in /proc/bus/i2c
|
|
|
|
# $_[1]: Algorithm description as found in /proc/bus/i2c
|
1999-02-19 18:11:03 +00:00
|
|
|
sub find_adapter_driver
|
|
|
|
{
|
|
|
|
my $adapter;
|
|
|
|
for $adapter (@pci_adapters) {
|
1999-02-23 14:14:32 +00:00
|
|
|
return $adapter->{driver} if &{$adapter->{match}} ($_[0],$_[1]);
|
1999-02-19 18:11:03 +00:00
|
|
|
}
|
|
|
|
return "?????";
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
# To do: support i2c-level access (through sysread/syswrite, probably).
|
|
|
|
# I can't test this at all (PIIX4 does not support this), so I have not
|
|
|
|
# included it.
|
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
use vars qw($IOCTL_I2C_RETRIES $IOCTL_I2C_TIMEOUT $IOCTL_I2C_UDELAY
|
|
|
|
$IOCTL_I2C_MDELAY $IOCTL_I2C_SLAVE $IOCTL_I2C_TENBIT
|
|
|
|
$IOCTL_I2C_SMBUS);
|
|
|
|
|
|
|
|
# These are copied from <linux/i2c.h> and <linux/smbus.h>
|
|
|
|
|
|
|
|
# For bit-adapters:
|
|
|
|
$IOCTL_I2C_RETRIES = 0x0701;
|
|
|
|
$IOCTL_I2C_TIMEOUT = 0x0702;
|
|
|
|
$IOCTL_I2C_UDELAY = 0x0705;
|
|
|
|
$IOCTL_I2C_MDELAY = 0x0706;
|
|
|
|
|
1999-02-17 23:24:24 +00:00
|
|
|
# General ones:
|
1999-02-17 20:55:23 +00:00
|
|
|
$IOCTL_I2C_SLAVE = 0x0703;
|
|
|
|
$IOCTL_I2C_TENBIT = 0x0704;
|
|
|
|
$IOCTL_I2C_SMBUS = 0x0720;
|
|
|
|
|
1999-02-17 23:24:24 +00:00
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
use vars qw($SMBUS_READ $SMBUS_WRITE $SMBUS_QUICK $SMBUS_BYTE $SMBUS_BYTE_DATA
|
|
|
|
$SMBUS_WORD_DATA $SMBUS_PROC_CALL $SMBUS_BLOCK_DATA);
|
1999-02-17 23:24:24 +00:00
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
# These are copied from <linux/smbus.h>
|
1999-02-17 23:24:24 +00:00
|
|
|
|
1999-02-17 20:55:23 +00:00
|
|
|
$SMBUS_READ = 1;
|
|
|
|
$SMBUS_WRITE = 0;
|
|
|
|
$SMBUS_QUICK = 0;
|
|
|
|
$SMBUS_BYTE = 1;
|
|
|
|
$SMBUS_BYTE_DATA = 2;
|
|
|
|
$SMBUS_WORD_DATA = 3;
|
|
|
|
$SMBUS_PROC_CALL = 4;
|
|
|
|
$SMBUS_BLOCK_DATA = 5;
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
my ($file,$addr) = @_;
|
|
|
|
ioctl $file, $IOCTL_I2C_SLAVE, $addr or return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
# 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.
|
|
|
|
# Exact calling conventions are intricate; read i2c-dev.c if you really need
|
|
|
|
# to know.
|
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# $_[1]: $SMBUS_READ for reading, $SMBUS_WRITE for writing
|
|
|
|
# $_[2]: Command (usually register number)
|
|
|
|
# $_[3]: Transaction kind ($SMBUS_BYTE, $SMBUS_BYTE_DATA, etc.)
|
|
|
|
# $_[4]: Reference to an array used for input/output of data
|
|
|
|
# Returns: 0 on failure, 1 on success.
|
1999-02-18 00:19:19 +00:00
|
|
|
# Note that we need to get back to Integer boundaries through the 'x2'
|
|
|
|
# in the pack. This is very compiler-dependent; I wish there was some other
|
|
|
|
# way to do this.
|
1999-02-17 20:55:23 +00:00
|
|
|
sub i2c_smbus_access
|
|
|
|
{
|
|
|
|
my ($file,$read_write,$command,$size,$data) = @_;
|
|
|
|
my $data_array = pack "C32", @$data;
|
1999-02-18 00:19:19 +00:00
|
|
|
my $ioctl_data = pack "C2x2Ip", ($read_write,$command,$size,$data_array);
|
1999-02-17 20:55:23 +00:00
|
|
|
ioctl $file, $IOCTL_I2C_SMBUS, $ioctl_data or return 0;
|
|
|
|
$_[4] = [ unpack "C32",$data_array ];
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
1999-02-17 23:24:24 +00:00
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# $_[1]: Either 0 or 1
|
|
|
|
# Returns: -1 on failure, the 0 on success.
|
|
|
|
sub i2c_smbus_write_quick
|
|
|
|
{
|
|
|
|
my ($file,$value) = @_;
|
|
|
|
my $data = [];
|
|
|
|
i2c_smbus_access $file, $value, 0, $SMBUS_QUICK, $data
|
|
|
|
or return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# Returns: -1 on failure, the read byte on success.
|
|
|
|
sub i2c_smbus_read_byte
|
|
|
|
{
|
|
|
|
my ($file) = @_;
|
|
|
|
my $data = [];
|
|
|
|
i2c_smbus_access $file, $SMBUS_READ, 0, $SMBUS_BYTE, $data
|
|
|
|
or return -1;
|
|
|
|
return $$data[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# $_[1]: Byte to write
|
|
|
|
# Returns: -1 on failure, 0 on success.
|
|
|
|
sub i2c_smbus_write_byte
|
1999-02-17 20:55:23 +00:00
|
|
|
{
|
|
|
|
my ($file,$command) = @_;
|
1999-02-17 23:24:24 +00:00
|
|
|
my $data = [$command];
|
|
|
|
i2c_smbus_access $file, $SMBUS_WRITE, 0, $SMBUS_BYTE, $data
|
1999-02-17 20:55:23 +00:00
|
|
|
or return -1;
|
1999-02-17 23:24:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# $_[1]: Command byte (usually register number)
|
|
|
|
# Returns: -1 on failure, the read byte on success.
|
|
|
|
sub i2c_smbus_read_byte_data
|
|
|
|
{
|
|
|
|
my ($file,$command) = @_;
|
|
|
|
my $data = [];
|
|
|
|
i2c_smbus_access $file, $SMBUS_READ, $command, $SMBUS_BYTE_DATA, $data
|
|
|
|
or return -1;
|
|
|
|
return $$data[0];
|
1999-02-17 20:55:23 +00:00
|
|
|
}
|
|
|
|
|
1999-02-17 23:24:24 +00:00
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# $_[1]: Command byte (usually register number)
|
|
|
|
# $_[2]: Byte to write
|
|
|
|
# Returns: -1 on failure, 0 on success.
|
|
|
|
sub i2c_smbus_write_byte_data
|
|
|
|
{
|
|
|
|
my ($file,$command,$value) = @_;
|
|
|
|
my $data = [$value];
|
|
|
|
i2c_smbus_access $file, $SMBUS_WRITE, $command, $SMBUS_BYTE_DATA, $data
|
|
|
|
or return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
# $_[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.
|
1999-02-17 23:24:24 +00:00
|
|
|
# Note: some devices use the wrong endiannes; use swap_bytes to correct for
|
|
|
|
# this.
|
1999-02-18 00:19:19 +00:00
|
|
|
sub i2c_smbus_read_word_data
|
1999-02-17 23:24:24 +00:00
|
|
|
{
|
1999-02-18 00:19:19 +00:00
|
|
|
my ($file,$command) = @_;
|
|
|
|
my $data = [];
|
|
|
|
i2c_smbus_access $file, $SMBUS_READ, $command, $SMBUS_WORD_DATA, $data
|
1999-02-17 23:24:24 +00:00
|
|
|
or return -1;
|
1999-02-18 00:19:19 +00:00
|
|
|
return $$data[0] + 256 * $$data[1];
|
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
|
|
|
# $_[2]: Byte to write
|
|
|
|
# Returns: -1 on failure, 0 on success.
|
1999-02-17 23:24:24 +00:00
|
|
|
# Note: some devices use the wrong endiannes; use swap_bytes to correct for
|
|
|
|
# this.
|
1999-02-18 00:19:19 +00:00
|
|
|
sub i2c_smbus_write_word_data
|
1999-02-17 20:55:23 +00:00
|
|
|
{
|
1999-02-18 00:19:19 +00:00
|
|
|
my ($file,$command,$value) = @_;
|
|
|
|
my $data = [$value & 0xff, $value >> 8];
|
|
|
|
i2c_smbus_access $file, $SMBUS_WRITE, $command, $SMBUS_WORD_DATA, $data
|
1999-02-17 20:55:23 +00:00
|
|
|
or return -1;
|
1999-02-18 00:19:19 +00:00
|
|
|
return 0;
|
1999-02-17 20:55:23 +00:00
|
|
|
}
|
1999-02-17 23:24:24 +00:00
|
|
|
|
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# $_[1]: Command byte (usually register number)
|
|
|
|
# $_[2]: Word to write
|
|
|
|
# Returns: -1 on failure, read word on success.
|
|
|
|
# Note: some devices use the wrong endiannes; use swap_bytes to correct for
|
|
|
|
# this.
|
|
|
|
sub i2c_smbus_process_call
|
|
|
|
{
|
|
|
|
my ($file,$command,$value) = @_;
|
|
|
|
my $data = [$value & 0xff, $value >> 8];
|
|
|
|
i2c_smbus_access $file, $SMBUS_WRITE, $command, $SMBUS_PROC_CALL, $data
|
|
|
|
or return -1;
|
|
|
|
return $$data[0] + 256 * $$data[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# $_[1]: Command byte (usually register number)
|
|
|
|
# Returns: Undefined on failure, a list of read bytes on success
|
|
|
|
# Note: some devices use the wrong endiannes; use swap_bytes to correct for
|
|
|
|
# this.
|
|
|
|
sub i2c_smbus_read_block_data
|
|
|
|
{
|
|
|
|
my ($file,$command) = @_;
|
|
|
|
my $data = [];
|
|
|
|
i2c_smbus_access $file, $SMBUS_READ, $command, $SMBUS_BLOCK_DATA, $data
|
|
|
|
or return;
|
|
|
|
shift @$data;
|
|
|
|
return @$data;
|
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: Reference to an opened filehandle
|
|
|
|
# $_[1]: Command byte (usually register number)
|
|
|
|
# @_[2..]: List of values to write
|
|
|
|
# Returns: -1 on failure, 0 on success.
|
|
|
|
# Note: some devices use the wrong endiannes; use swap_bytes to correct for
|
|
|
|
# this.
|
1999-02-18 00:19:19 +00:00
|
|
|
sub i2c_smbus_write_block_data
|
1999-02-17 23:24:24 +00:00
|
|
|
{
|
|
|
|
my ($file,$command,@data) = @_;
|
|
|
|
i2c_smbus_access $file, $SMBUS_WRITE, $command, $SMBUS_BLOCK_DATA, \@data
|
|
|
|
or return;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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';
|
1999-02-19 18:11:03 +00:00
|
|
|
# with field 'misdetected'
|
|
|
|
# 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
|
|
|
|
# in /proc/bus/i2c (if this is an I2C detection)
|
|
|
|
# with field 'i2c_algo' containing an algorithm string as appearing
|
|
|
|
# in /proc/bus/i2c (if this is an I2C detection)
|
|
|
|
# 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)
|
1999-03-23 21:48:41 +00:00
|
|
|
# with field 'i2c_extra' if this is an I2C detection and the address
|
|
|
|
# is not normally probed by the kernel driver
|
1999-02-28 17:41:46 +00:00
|
|
|
# with field 'isa_addr' containing the ISA address this chip is on
|
|
|
|
# (if this is an ISA detection)
|
1999-03-23 21:48:41 +00:00
|
|
|
# with field 'isa_extra' if this is an ISA detection and the address
|
|
|
|
# is not normally probed by the kernel driver
|
1999-02-28 17:41:46 +00:00
|
|
|
# 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
|
|
|
{
|
1999-02-23 14:14:32 +00:00
|
|
|
my ($chipdriver,$datahash) = @_;
|
1999-02-28 17:41:46 +00:00
|
|
|
my ($i,$new_detected_ref,$new_misdetected_ref,$detected_ref,$misdetected_ref,
|
|
|
|
$main_entry,$detected_entry,$put_in_detected,@hash_addrs,@entry_addrs);
|
|
|
|
|
|
|
|
# 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,
|
|
|
|
detected => [],
|
|
|
|
misdetected => [] };
|
|
|
|
}
|
|
|
|
$new_detected_ref = $chips_detected[$i]->{detected};
|
|
|
|
$new_misdetected_ref = $chips_detected[$i]->{misdetected};
|
|
|
|
|
1999-02-28 17:41:46 +00:00
|
|
|
# Find out whether our new entry should go into the detected or the
|
1999-03-02 08:08:29 +00:00
|
|
|
# misdetected list. We compare all i2c addresses; if at least one matches,
|
|
|
|
# but our conf value is lower, we assume this is a misdetect.
|
|
|
|
@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
|
1999-03-02 08:08:29 +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) {
|
|
|
|
# Here, we move all entries from detected to misdetected which
|
|
|
|
# match at least in one main or sub address. This may not be the
|
|
|
|
# best idea to do, as it may remove detections without replacing
|
|
|
|
# them with second-best ones. Too bad.
|
|
|
|
@hash_addrs = ($datahash->{i2c_addr});
|
|
|
|
push @hash_addrs, @{$datahash->{i2c_sub_addrs}}
|
|
|
|
if exists $datahash->{i2c_sub_addrs};
|
|
|
|
foreach $main_entry (@chips_detected) {
|
|
|
|
$detected_ref = $main_entry->{detected};
|
|
|
|
$misdetected_ref = $main_entry->{misdetected};
|
|
|
|
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};
|
|
|
|
if (any_list_match \@entry_addrs, \@hash_addrs) {
|
|
|
|
push @$misdetected_ref,$detected_ref->[$i];
|
|
|
|
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;
|
|
|
|
} else {
|
|
|
|
# No hard work here
|
|
|
|
push @$new_misdetected_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
|
|
|
|
# Returns: Nothing
|
1999-02-23 14:14:32 +00:00
|
|
|
sub add_isa_to_chips_detected
|
|
|
|
{
|
1999-02-23 20:28:05 +00:00
|
|
|
my ($alias_detect,$chipdriver,$datahash) = @_;
|
1999-02-28 17:41:46 +00:00
|
|
|
my ($i,$new_detected_ref,$new_misdetected_ref,$detected_ref,$misdetected_ref,
|
|
|
|
$main_entry);
|
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.
|
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,
|
|
|
|
detected => [],
|
1999-02-28 17:41:46 +00:00
|
|
|
misdetected => [] };
|
1999-02-23 14:14:32 +00:00
|
|
|
}
|
|
|
|
$new_detected_ref = $chips_detected[$i]->{detected};
|
|
|
|
$new_misdetected_ref = $chips_detected[$i]->{misdetected};
|
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.
|
1999-02-28 17:41:46 +00:00
|
|
|
# If an alias is found in the misdetected list, we add the new information
|
|
|
|
# and terminate this function. If it is found in the detected list, we
|
|
|
|
# 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.
|
|
|
|
|
|
|
|
# Misdetected alias detection:
|
|
|
|
for ($i = 0; $i < @$new_misdetected_ref; $i++) {
|
|
|
|
if (exists $new_misdetected_ref->[$i]->{i2c_addr} and
|
|
|
|
not exists $new_misdetected_ref->[$i]->{isa_addr} and
|
1999-02-23 20:28:05 +00:00
|
|
|
defined $alias_detect and
|
1999-02-28 17:41:46 +00:00
|
|
|
$new_misdetected_ref->[$i]->{chipname} eq $datahash->{chipname}) {
|
1999-03-01 16:18:28 +00:00
|
|
|
open FILE,"/dev/i2c-$new_misdetected_ref->[$i]->{i2c_devnr}" or
|
1999-02-24 01:33:18 +00:00
|
|
|
print("Can't open ",
|
1999-03-01 16:18:28 +00:00
|
|
|
"/dev/i2c-$new_misdetected_ref->[$i]->{i2c_devnr}?!?\n"),
|
1999-02-24 01:33:18 +00:00
|
|
|
next;
|
1999-03-02 10:04:21 +00:00
|
|
|
i2c_set_slave_addr \*FILE,$new_misdetected_ref->[$i]->{i2c_addr} or
|
1999-02-25 08:37:29 +00:00
|
|
|
print("Can't set I2C address for ",
|
1999-03-01 16:18:28 +00:00
|
|
|
"/dev/i2c-$new_misdetected_ref->[$i]->{i2c_devnr}?!?\n"),
|
1999-02-25 08:37:29 +00:00
|
|
|
next;
|
1999-02-24 01:12:05 +00:00
|
|
|
if (&$alias_detect ($datahash->{isa_addr},\*FILE,
|
1999-02-28 17:41:46 +00:00
|
|
|
$new_misdetected_ref->[$i]->{i2c_addr})) {
|
|
|
|
$new_misdetected_ref->[$i]->{isa_addr} = $datahash->{isa_addr};
|
1999-03-23 21:48:41 +00:00
|
|
|
$new_misdetected_ref->[$i]->{isa_extra} = $datahash->{isa_extra}
|
|
|
|
if exists $datahash->{isa_extra};
|
1999-02-25 12:23:04 +00:00
|
|
|
close FILE;
|
1999-02-23 20:28:05 +00:00
|
|
|
return;
|
|
|
|
}
|
1999-02-24 01:12:05 +00:00
|
|
|
close FILE;
|
1999-02-23 20:28:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-02-28 17:41:46 +00:00
|
|
|
# Detected alias detection:
|
|
|
|
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}) {
|
1999-03-01 16:18:28 +00:00
|
|
|
open FILE,"/dev/i2c-$new_detected_ref->[$i]->{i2c_devnr}" or
|
1999-02-24 01:33:18 +00:00
|
|
|
print("Can't open ",
|
1999-03-01 16:18:28 +00:00
|
|
|
"/dev/i2c-$new_detected_ref->[$i]->{i2c_devnr}?!?\n"),
|
1999-02-24 01:33:18 +00:00
|
|
|
next;
|
1999-03-03 14:18:01 +00:00
|
|
|
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 ",
|
1999-03-01 16:18:28 +00:00
|
|
|
"/dev/i2c-$new_detected_ref->[$i]->{i2c_devnr}?!?\n"),
|
1999-02-25 08:37:29 +00:00
|
|
|
next;
|
1999-02-24 01:12:05 +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};
|
1999-03-23 21:48:41 +00:00
|
|
|
$new_detected_ref->[$i]->{isa_extra} = $datahash->{isa_extra}
|
|
|
|
if exists $datahash->{isa_extra};
|
1999-02-28 17:41:46 +00:00
|
|
|
($datahash) = splice (@$new_detected_ref, $i, 1);
|
1999-02-25 12:23:04 +00:00
|
|
|
close FILE;
|
1999-02-23 20:28:05 +00:00
|
|
|
last;
|
|
|
|
}
|
1999-02-24 01:33:18 +00:00
|
|
|
close FILE;
|
1999-02-23 20:28:05 +00:00
|
|
|
}
|
|
|
|
}
|
1999-02-28 17:41:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
# Find out whether our new entry should go into the detected or the
|
|
|
|
# misdetected list. We only compare main isa_addr here, of course.
|
|
|
|
foreach $main_entry (@chips_detected) {
|
|
|
|
$detected_ref = $main_entry->{detected};
|
|
|
|
$misdetected_ref = $main_entry->{misdetected};
|
|
|
|
for ($i = 0; $i < @{$main_entry->{detected}}; $i++) {
|
|
|
|
if (exists $detected_ref->[$i]->{isa_addr} and
|
|
|
|
$detected_ref->[$i]->{isa_addr} == $datahash->{isa_addr}) {
|
|
|
|
if ($detected_ref->[$i]->{conf} >= $datahash->{conf}) {
|
1999-02-23 14:14:32 +00:00
|
|
|
push @$new_misdetected_ref, $datahash;
|
1999-02-28 17:41:46 +00:00
|
|
|
} else {
|
|
|
|
push @$misdetected_ref,$detected_ref->[$i];
|
|
|
|
splice @$detected_ref, $i,1;
|
|
|
|
push @$new_detected_ref, $datahash;
|
1999-02-23 14:14:32 +00:00
|
|
|
}
|
1999-02-28 17:41:46 +00:00
|
|
|
return;
|
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-02-23 14:14:32 +00:00
|
|
|
}
|
|
|
|
|
1999-02-18 00:19:19 +00:00
|
|
|
# $_[0]: The number of the adapter to scan
|
1999-02-19 18:11:03 +00:00
|
|
|
# $_[1]: The name of the adapter, as appearing in /proc/bus/i2c
|
1999-02-23 14:14:32 +00:00
|
|
|
# $_[2]: The name of the algorithm, as appearing in /proc/bus/i2c
|
|
|
|
# $_[3]: The driver of the adapter
|
1999-03-02 08:08:29 +00:00
|
|
|
# @_[4..]: Addresses not to scan
|
1999-02-18 00:19:19 +00:00
|
|
|
sub scan_adapter
|
1999-02-17 23:24:24 +00:00
|
|
|
{
|
1999-02-24 00:22:52 +00:00
|
|
|
my ( $adapter_nr,$adapter_name,$algorithm_name,$adapter_driver,
|
|
|
|
$not_to_scan) = @_;
|
1999-02-28 17:41:46 +00:00
|
|
|
my ($chip, $addr, $conf,@chips,$new_hash,$other_addr);
|
|
|
|
|
|
|
|
# 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
|
|
|
|
1999-02-19 18:11:03 +00:00
|
|
|
open FILE,"/dev/i2c-$adapter_nr" or
|
1999-02-24 01:12:05 +00:00
|
|
|
(print "Can't open /dev/i2c-$adapter_nr ($!)\n"), return;
|
1999-02-28 17:41:46 +00:00
|
|
|
|
|
|
|
# Now scan each address in turn
|
1999-02-18 18:09:14 +00:00
|
|
|
foreach $addr (0..0x7f) {
|
1999-02-28 17:41:46 +00:00
|
|
|
# As the not_to_scan list is sorted, we can check it fast
|
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
|
|
|
|
1999-02-18 18:09:14 +00:00
|
|
|
i2c_set_slave_addr(\*FILE,$addr) or print("Can't set address to $_?!?\n"),
|
1999-02-18 00:19:19 +00:00
|
|
|
next;
|
1999-02-28 17:41:46 +00:00
|
|
|
|
1999-02-18 18:09:14 +00:00
|
|
|
next unless i2c_smbus_read_byte(\*FILE) >= 0;
|
|
|
|
printf "Client found at address 0x%02x\n",$addr;
|
1999-02-28 17:41:46 +00:00
|
|
|
|
1999-02-18 18:09:14 +00:00
|
|
|
foreach $chip (@chip_ids) {
|
1999-02-23 20:28:05 +00:00
|
|
|
if (exists $$chip{i2c_addrs} and contains $addr, @{$$chip{i2c_addrs}}) {
|
1999-02-23 23:16:09 +00:00
|
|
|
print "Probing for `$$chip{name}'... ";
|
1999-02-19 01:52:29 +00:00
|
|
|
if (($conf,@chips) = &{$$chip{i2c_detect}} (\*FILE ,$addr)) {
|
1999-02-19 02:30:17 +00:00
|
|
|
print "Success!\n",
|
1999-02-19 01:52:29 +00:00
|
|
|
" (confidence $conf, driver `$$chip{driver}'";
|
|
|
|
if (@chips) {
|
1999-02-25 08:30:04 +00:00
|
|
|
print ", other addresses:";
|
1999-02-28 17:41:46 +00:00
|
|
|
@chips = sort @chips;
|
1999-02-25 08:30:04 +00:00
|
|
|
foreach $other_addr (sort @chips) {
|
1999-03-02 08:08:29 +00:00
|
|
|
printf(" 0x%02x",$other_addr);
|
1999-02-25 08:30:04 +00:00
|
|
|
}
|
1999-02-20 00:54:55 +00:00
|
|
|
}
|
1999-02-28 17:41:46 +00:00
|
|
|
printf "\n";
|
|
|
|
$new_hash = { conf => $conf,
|
|
|
|
i2c_addr => $addr,
|
|
|
|
chipname => $$chip{name},
|
|
|
|
i2c_adap => $adapter_name,
|
|
|
|
i2c_algo => $algorithm_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;
|
|
|
|
}
|
1999-03-23 21:48:41 +00:00
|
|
|
$new_hash->{i2c_extra} = 0
|
|
|
|
if exists $chip->{i2c_driver_addrs} and
|
|
|
|
not contains( $addr , @{$chip->{i2c_driver_addrs}});
|
1999-02-28 17:41:46 +00:00
|
|
|
add_i2c_to_chips_detected $$chip{driver}, $new_hash;
|
1999-02-18 18:09:14 +00:00
|
|
|
} else {
|
1999-02-19 18:11:03 +00:00
|
|
|
print "Failed!\n";
|
1999-02-18 18:09:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
|
{
|
|
|
|
my ($chip,$addr,$conf);
|
|
|
|
foreach $chip (@chip_ids) {
|
|
|
|
next if not exists $$chip{isa_addrs} or not exists $$chip{isa_detect};
|
1999-02-23 23:16:09 +00:00
|
|
|
print "Probing for `$$chip{name}'\n";
|
1999-02-23 14:14:32 +00:00
|
|
|
foreach $addr (@{$$chip{isa_addrs}}) {
|
1999-02-24 01:12:05 +00:00
|
|
|
if ($addr) {
|
|
|
|
printf " Trying address 0x%04x... ", $addr;
|
|
|
|
} else {
|
1999-02-28 17:41:46 +00:00
|
|
|
print " Trying general detect... ";
|
1999-02-24 01:12:05 +00:00
|
|
|
}
|
1999-02-23 14:14:32 +00:00
|
|
|
$conf = &{$$chip{isa_detect}} ($addr);
|
|
|
|
print("Failed!\n"), next if not defined $conf;
|
|
|
|
print "Success!\n";
|
|
|
|
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,
|
|
|
|
chipname => $$chip{name}
|
|
|
|
};
|
|
|
|
$new_hash->{isa_extra} = 0
|
|
|
|
if exists $chip->{isa_driver_addrs} and
|
|
|
|
not contains ($addr, @{$chip->{isa_driver_addrs}});
|
|
|
|
add_isa_to_chips_detected $$chip{alias_detect},$$chip{driver},$new_hash;
|
1999-02-23 14:14:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-02-18 18:09:14 +00:00
|
|
|
|
1999-02-18 00:19:19 +00:00
|
|
|
##################
|
|
|
|
# CHIP DETECTION #
|
|
|
|
##################
|
|
|
|
|
1999-02-18 18:09:14 +00:00
|
|
|
# Each function returns a confidence value. The higher this value, the more
|
1999-02-18 21:14:48 +00:00
|
|
|
# sure we are about this chip. A Winbond W83781D, for example, will be
|
|
|
|
# detected as a LM78 too; but as the Winbond detection has a higher confidence
|
|
|
|
# factor, you should identify it as a Winbond.
|
|
|
|
|
|
|
|
# Each function returns a list. The first element is the confidence value;
|
|
|
|
# Each element after it is an SMBus address. In this way, we can detect
|
|
|
|
# chips with several SMBus addresses. The SMBus address for which the
|
|
|
|
# function was called is never returned.
|
1999-02-18 18:09:14 +00:00
|
|
|
|
|
|
|
# If there are devices which get confused if they are only read from, then
|
|
|
|
# this program will surely confuse them. But we guarantee never to write to
|
|
|
|
# any of these devices.
|
|
|
|
|
|
|
|
|
|
|
|
# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
|
|
|
|
# $_[1]: A reference to the file descriptor to access this chip.
|
|
|
|
# We may assume an i2c_set_slave_addr was already done.
|
|
|
|
# $_[2]: Address
|
1999-02-18 21:14:48 +00:00
|
|
|
# Returns: undef if not detected, (7) if detected.
|
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
|
1999-02-18 21:14:48 +00:00
|
|
|
# Note that this function is always called through a closure, so the
|
|
|
|
# arguments are shifted by one place.
|
1999-02-18 18:09:14 +00:00
|
|
|
sub lm78_detect
|
|
|
|
{
|
|
|
|
my $reg;
|
|
|
|
my ($chip,$file,$addr) = @_;
|
1999-02-18 21:14:48 +00:00
|
|
|
return unless i2c_smbus_read_byte_data($file,0x48) == $addr;
|
1999-02-19 02:30:17 +00:00
|
|
|
return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
|
1999-02-18 18:09:14 +00:00
|
|
|
$reg = i2c_smbus_read_byte_data($file,0x49);
|
1999-02-18 21:14:48 +00:00
|
|
|
return unless ($chip == 0 and $reg == 0x00) or
|
|
|
|
($chip == 1 and $reg == 0x40) or
|
1999-02-19 02:30:17 +00:00
|
|
|
($chip == 2 and ($reg & 0xfe) == 0xc0);
|
1999-02-18 21:14:48 +00:00
|
|
|
return (7);
|
1999-02-18 18:09:14 +00:00
|
|
|
}
|
|
|
|
|
1999-02-22 20:40:16 +00:00
|
|
|
# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
|
1999-02-23 14:14:32 +00:00
|
|
|
# $_[1]: Address
|
1999-03-09 16:19:30 +00:00
|
|
|
# Returns: undef if not detected, 7 if detected.
|
1999-02-22 20:40:16 +00:00
|
|
|
# Note: Only address 0x290 is scanned at this moment.
|
|
|
|
sub lm78_isa_detect
|
|
|
|
{
|
1999-02-23 14:14:32 +00:00
|
|
|
my ($chip,$addr) = @_ ;
|
|
|
|
my $val = inb ($addr + 1);
|
|
|
|
return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or
|
1999-02-22 20:40:16 +00:00
|
|
|
inb ($addr + 7) != $val;
|
LM78 insmod parameters and better detection
Supported insmod parameters:
ignore, ignore_range
probe, probe_range
force, force_lm78, force_lm78j, force_lm79
force* overrules ignore* overrules probe*
The *_range parameters need three elements for each specification:
bus,start_addr,end_addr
The address ranges are inclusive.
The other parameters need two elements for each specification:
bus,addr
In each case, '-1' stands for 'any I2C bus', and 9191 stands for
'the ISA bus' (Bonus question: who can figure out why I choose 9191?)
In each case, just append if you want several specification, for example:
insmod lm78 probe=9191,0x2a0,1,0x56
force_* does no detection, not even chip detection; it blindly assumes
you know what you are doing. plain force does the chip detection, but
nothing else; but it can still fail if the register read-out does not
match a chip type.
Detection is done in exactly the same way as sensors-detect, except that
only the range 0x20-0x2f is examined by default. This needs to be
synchronized somehow with the detect script. I would rather scan the whole
I2C address range, but with those clueless PIIX4 hangs when clock chips
are read, that would simply give too much trouble.
The detect script has slightly better ISA detection now, too.
git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@325 7894878c-1315-0410-8ee3-d5d059ff63e0
1999-03-19 06:25:02 +00:00
|
|
|
|
|
|
|
$val = inb($addr + 5) & 0x7f;
|
|
|
|
outb($addr+5,~ $val);
|
|
|
|
if ((inb ($addr+5) & 0x7f) != (~ $val & 0x7f)) {
|
|
|
|
outb($addr+5,$val);
|
|
|
|
return;
|
|
|
|
}
|
1999-02-23 14:14:32 +00:00
|
|
|
my $readproc = sub { isa_read_byte $addr + 5, $addr + 6, @_ };
|
|
|
|
return unless (&$readproc(0x40) & 0x80) == 0x00;
|
|
|
|
my $reg = &$readproc(0x49);
|
|
|
|
return unless ($chip == 0 and $reg == 0x00) or
|
|
|
|
($chip == 1 and $reg == 0x40) or
|
|
|
|
($chip == 2 and ($reg & 0xfe) == 0xc0);
|
|
|
|
return 7;
|
1999-02-22 20:40:16 +00:00
|
|
|
}
|
|
|
|
|
1999-02-23 20:28:05 +00:00
|
|
|
|
|
|
|
# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
|
|
|
|
# $_[1]: ISA address
|
|
|
|
# $_[2]: I2C file handle
|
|
|
|
# $_[3]: I2C address
|
|
|
|
sub lm78_alias_detect
|
|
|
|
{
|
|
|
|
my ($chip,$isa_addr,$file,$i2c_addr) = @_;
|
|
|
|
my $i;
|
|
|
|
my $readproc = sub { isa_read_byte $isa_addr + 5, $isa_addr + 6, @_ };
|
|
|
|
return 0 unless &$readproc(0x48) == $i2c_addr;
|
|
|
|
for ($i = 0x2b; $i <= 0x3d; $i ++) {
|
1999-02-24 01:33:18 +00:00
|
|
|
return 0 unless &$readproc($i) == i2c_smbus_read_byte_data($file,$i);
|
1999-02-23 20:28:05 +00:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
1999-02-18 18:09:14 +00:00
|
|
|
# $_[0]: A reference to the file descriptor to access this chip.
|
|
|
|
# We may assume an i2c_set_slave_addr was already done.
|
1999-02-18 00:19:19 +00:00
|
|
|
# $_[1]: Address
|
1999-02-18 21:14:48 +00:00
|
|
|
# Returns: undef if not detected, (3) if detected.
|
1999-02-18 18:09:14 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x01: Configuration
|
|
|
|
# 0x02: Hysteris
|
|
|
|
# 0x03: Overtemperature Shutdown
|
|
|
|
# Detection really sucks! It is only based on the fact that the LM75 has only
|
|
|
|
# four registers. Any other chip in the valid address range with only four
|
|
|
|
# registers will be detected too.
|
|
|
|
# Note that register $00 may change, so we can't use the modulo trick on it.
|
|
|
|
sub lm75_detect
|
|
|
|
{
|
|
|
|
my $i;
|
|
|
|
my ($file,$addr) = @_;
|
1999-03-01 13:49:06 +00:00
|
|
|
my $cur = i2c_smbus_read_word_data($file,0x00);
|
1999-02-18 18:09:14 +00:00
|
|
|
my $conf = i2c_smbus_read_byte_data($file,0x01);
|
|
|
|
my $hyst = i2c_smbus_read_word_data($file,0x02);
|
|
|
|
my $os = i2c_smbus_read_word_data($file,0x03);
|
1999-03-01 13:49:06 +00:00
|
|
|
return if $hyst & 0x7f00 or $os & 0x7f00 or $cur & 0x7f00;
|
|
|
|
for ($i = 0x00; $i <= 0x1f; $i += 1) {
|
|
|
|
return if i2c_smbus_read_byte_data($file,($i * 0x08) + 0x01) != $conf;
|
|
|
|
return if i2c_smbus_read_word_data($file,($i * 0x08) + 0x02) != $hyst;
|
|
|
|
return if i2c_smbus_read_word_data($file,($i * 0x08) + 0x03) != $os;
|
1999-02-18 18:09:14 +00:00
|
|
|
}
|
1999-02-18 21:14:48 +00:00
|
|
|
return (3);
|
1999-02-18 18:09:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# $_[0]: A reference to the file descriptor to access this chip.
|
|
|
|
# We may assume an i2c_set_slave_addr was already done.
|
|
|
|
# $_[1]: Address
|
1999-02-18 21:14:48 +00:00
|
|
|
# Returns: undef if not detected, (3) if detected.
|
1999-02-18 18:09:14 +00:00
|
|
|
# Registers used:
|
|
|
|
# Registers used:
|
|
|
|
# 0x02: Interrupt state register
|
|
|
|
# How to detect this beast?
|
|
|
|
sub lm80_detect
|
|
|
|
{
|
|
|
|
my $i;
|
|
|
|
my ($file,$addr) = @_;
|
1999-02-19 02:30:17 +00:00
|
|
|
return if (i2c_smbus_read_byte_data($file,$0x02) & 0xc0) != 0;
|
1999-02-18 18:09:14 +00:00
|
|
|
for ($i = 0x2a; $i <= 0x3d; $i++) {
|
|
|
|
my $reg = i2c_smbus_read_byte_data($file,$i);
|
1999-02-18 21:14:48 +00:00
|
|
|
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
|
|
|
}
|
1999-02-18 21:14:48 +00:00
|
|
|
return (3);
|
1999-02-18 18:09:14 +00:00
|
|
|
}
|
|
|
|
|
1999-02-22 18:20:35 +00:00
|
|
|
# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 3 = W83783S)
|
|
|
|
# $_[1]: A reference to the file descriptor to access this chip.
|
1999-02-18 21:14:48 +00:00
|
|
|
# We may assume an i2c_set_slave_addr was already done.
|
1999-02-22 18:20:35 +00:00
|
|
|
# $_[2]: Address
|
1999-02-18 21:14:48 +00:00
|
|
|
# Returns: undef if not detected, (8,addr1,addr2) if detected, but only
|
|
|
|
# if the LM75 chip emulation is enabled.
|
|
|
|
# Registers used:
|
|
|
|
# 0x48: Full I2C Address
|
|
|
|
# 0x4a: I2C addresses of emulated LM75 chips
|
|
|
|
# 0x4e: Vendor ID byte selection, and bank selection
|
|
|
|
# 0x4f: Vendor ID
|
1999-02-22 18:20:35 +00:00
|
|
|
# 0x58: Device ID (only when in bank 0); both 0x10 and 0x11 is seen for
|
|
|
|
# W83781D though Winbond documents 0x10 only.
|
|
|
|
# Note: Fails if the W8378xD is not in bank 0!
|
1999-02-18 21:14:48 +00:00
|
|
|
# Note: Detection overrules a previous LM78 detection
|
|
|
|
sub w83781d_detect
|
|
|
|
{
|
|
|
|
my ($reg1,$reg2,@res);
|
|
|
|
my ($chip,$file,$addr) = @_;
|
|
|
|
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);
|
1999-02-19 02:30:17 +00:00
|
|
|
return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or
|
|
|
|
(($reg1 & 0x80) == 0x80 and $reg2 == 0x5c);
|
1999-02-22 20:40:16 +00:00
|
|
|
return unless ($reg1 & 0x07) == 0x00;
|
1999-03-24 21:28:22 +00:00
|
|
|
$reg1 = i2c_smbus_read_byte_data($file,0x58) & 0xfe;
|
1999-03-18 15:12:01 +00:00
|
|
|
return if $chip == 0 and $reg1 != 0x10;
|
1999-02-22 18:20:35 +00:00
|
|
|
return if $chip == 1 and $reg1 != 0x30;
|
|
|
|
return if $chip == 2 and $reg1 != 0x40;
|
1999-02-18 21:14:48 +00:00
|
|
|
$reg1 = i2c_smbus_read_byte_data($file,0x4a);
|
|
|
|
@res = (8);
|
1999-02-20 14:40:24 +00:00
|
|
|
push @res, ($reg1 & 0x07) + 0x48 unless $reg1 & 0x08;
|
|
|
|
push @res, (($reg1 & 0x80) >> 4) + 0x48 unless $reg1 & 0x80;
|
1999-02-18 21:14:48 +00:00
|
|
|
return @res;
|
|
|
|
}
|
|
|
|
|
1999-02-23 20:28:05 +00:00
|
|
|
# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 3 = W83783S)
|
|
|
|
# $_[1]: ISA address
|
|
|
|
# $_[2]: I2C file handle
|
|
|
|
# $_[3]: I2C address
|
|
|
|
sub w83781d_alias_detect
|
|
|
|
{
|
|
|
|
my ($chip,$isa_addr,$file,$i2c_addr) = @_;
|
|
|
|
my $i;
|
|
|
|
my $readproc = sub { isa_read_byte $isa_addr + 5, $isa_addr + 6, @_ };
|
|
|
|
return 0 unless &$readproc(0x48) == $i2c_addr;
|
|
|
|
for ($i = 0x2b; $i <= 0x3d; $i ++) {
|
1999-02-24 01:33:18 +00:00
|
|
|
return 0 unless &$readproc($i) == i2c_smbus_read_byte_data($file,$i);
|
1999-02-23 20:28:05 +00:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
1999-02-22 20:40:16 +00:00
|
|
|
# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 3 = W83783S)
|
1999-02-23 14:14:32 +00:00
|
|
|
# $_[1]: Address
|
1999-02-22 20:40:16 +00:00
|
|
|
# Returns: undef if not detected, (8) if detected.
|
|
|
|
sub w83781d_isa_detect
|
|
|
|
{
|
1999-02-23 14:14:32 +00:00
|
|
|
my ($chip,$addr) = @_ ;
|
1999-04-02 22:38:47 +00:00
|
|
|
my ($reg1,$reg2);
|
1999-02-23 14:14:32 +00:00
|
|
|
my $val = inb ($addr + 1);
|
1999-03-24 21:28:22 +00:00
|
|
|
return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or
|
1999-02-22 20:40:16 +00:00
|
|
|
inb ($addr + 7) != $val;
|
LM78 insmod parameters and better detection
Supported insmod parameters:
ignore, ignore_range
probe, probe_range
force, force_lm78, force_lm78j, force_lm79
force* overrules ignore* overrules probe*
The *_range parameters need three elements for each specification:
bus,start_addr,end_addr
The address ranges are inclusive.
The other parameters need two elements for each specification:
bus,addr
In each case, '-1' stands for 'any I2C bus', and 9191 stands for
'the ISA bus' (Bonus question: who can figure out why I choose 9191?)
In each case, just append if you want several specification, for example:
insmod lm78 probe=9191,0x2a0,1,0x56
force_* does no detection, not even chip detection; it blindly assumes
you know what you are doing. plain force does the chip detection, but
nothing else; but it can still fail if the register read-out does not
match a chip type.
Detection is done in exactly the same way as sensors-detect, except that
only the range 0x20-0x2f is examined by default. This needs to be
synchronized somehow with the detect script. I would rather scan the whole
I2C address range, but with those clueless PIIX4 hangs when clock chips
are read, that would simply give too much trouble.
The detect script has slightly better ISA detection now, too.
git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@325 7894878c-1315-0410-8ee3-d5d059ff63e0
1999-03-19 06:25:02 +00:00
|
|
|
|
|
|
|
$val = inb($addr + 5) & 0x7f;
|
|
|
|
outb($addr+5,~ $val);
|
|
|
|
if ((inb ($addr+5) & 0x7f) != (~ $val & 0x7f)) {
|
|
|
|
outb($addr+5,$val);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-02-23 14:14:32 +00:00
|
|
|
my $read_proc = sub { isa_read_byte $addr + 5, $addr + 6, @_ };
|
|
|
|
$reg1 = &$read_proc(0x4e);
|
|
|
|
$reg2 = &$read_proc(0x4f);
|
|
|
|
return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or
|
|
|
|
(($reg1 & 0x80) == 0x80 and $reg2 == 0x5c);
|
|
|
|
return unless ($reg1 & 0x07) == 0x00;
|
1999-03-24 21:28:22 +00:00
|
|
|
$reg1 = &$read_proc(0x58) & 0xfe;
|
|
|
|
return if $chip == 0 and $reg1 != 0x10;
|
1999-02-23 14:14:32 +00:00
|
|
|
return if $chip == 1 and $reg1 != 0x30;
|
|
|
|
return if $chip == 2 and $reg1 != 0x40;
|
1999-02-24 01:16:40 +00:00
|
|
|
return 8;
|
1999-02-22 20:40:16 +00:00
|
|
|
}
|
|
|
|
|
1999-02-18 21:14:48 +00:00
|
|
|
# $_[0]: Chip to detect (0 = Revision 0x00, 1 = Revision 0x80)
|
|
|
|
# $_[1]: A reference to the file descriptor to access this chip.
|
|
|
|
# We may assume an i2c_set_slave_addr was already done.
|
|
|
|
# $_[2]: Address
|
|
|
|
# Returns: undef if not detected, (6) if detected.
|
|
|
|
# Registers used:
|
|
|
|
# 0x00: Device ID
|
|
|
|
# 0x01: Revision ID
|
|
|
|
# 0x03: Configuration
|
|
|
|
# Mediocre detection
|
|
|
|
sub gl518sm_detect
|
|
|
|
{
|
|
|
|
my $reg;
|
|
|
|
my ($chip,$file,$addr) = @_;
|
|
|
|
return unless i2c_smbus_read_byte_data($file,0x00) == 0x80;
|
1999-02-19 02:30:17 +00:00
|
|
|
return unless (i2c_smbus_read_byte_data($file,0x03) & 0x80) == 0x00;
|
1999-02-18 21:14:48 +00:00
|
|
|
$reg = i2c_smbus_read_byte_data($file,0x01);
|
|
|
|
return unless ($chip == 0 and $reg == 0x00) or
|
|
|
|
($chip == 1 and $reg == 0x80);
|
|
|
|
return (6);
|
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: A reference to the file descriptor to access this chip.
|
|
|
|
# We may assume an i2c_set_slave_addr was already done.
|
|
|
|
# $_[1]: Address
|
|
|
|
# Returns: undef if not detected, (5) if detected.
|
|
|
|
# Registers used:
|
|
|
|
# 0x00: Device ID
|
|
|
|
# 0x01: Revision ID
|
|
|
|
# 0x03: Configuration
|
|
|
|
# Mediocre detection
|
|
|
|
sub gl520sm_detect
|
|
|
|
{
|
|
|
|
my ($file,$addr) = @_;
|
|
|
|
return unless i2c_smbus_read_byte_data($file,0x00) == 0x20;
|
1999-02-19 02:30:17 +00:00
|
|
|
return unless (i2c_smbus_read_byte_data($file,0x03) & 0x80) == 0x00;
|
1999-02-18 21:14:48 +00:00
|
|
|
# The line below must be better checked before I dare to use it.
|
|
|
|
# return unless i2c_smbus_read_byte_data($file,0x01) == 0x00;
|
|
|
|
return (5);
|
|
|
|
}
|
|
|
|
|
1999-03-29 00:58:55 +00:00
|
|
|
# $_[0]: Chip to detect (0 = ADM9240, 1 = DS1780)
|
|
|
|
# $_[1]: A reference to the file descriptor to access this chip.
|
1999-02-18 21:14:48 +00:00
|
|
|
# We may assume an i2c_set_slave_addr was already done.
|
1999-03-29 00:58:55 +00:00
|
|
|
# $_[2]: Address
|
|
|
|
# Returns: undef if not detected, (8) if detected.
|
1999-02-18 21:14:48 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0x3e: Company ID
|
|
|
|
# 0x40: Configuration
|
|
|
|
# 0x48: Full I2C Address
|
|
|
|
# Note: Detection overrules a previous LM78 detection
|
|
|
|
sub adm9240_detect
|
|
|
|
{
|
1999-03-29 00:58:55 +00:00
|
|
|
my $reg;
|
|
|
|
my ($chip, $file,$addr) = @_;
|
|
|
|
$reg = i2c_smbus_read_byte_data($file,0x3e);
|
|
|
|
return unless ($chip == 0 and $reg == 0x23) or
|
|
|
|
($chip == 1 and $reg == 0xda);
|
1999-02-19 02:30:17 +00:00
|
|
|
return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
|
1999-02-18 21:14:48 +00:00
|
|
|
return unless i2c_smbus_read_byte_data($file,0x48) == $addr;
|
|
|
|
|
|
|
|
return (8);
|
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: Chip to detect (0 = ADM1021, 1 = MAX1617)
|
|
|
|
# $_[1]: A reference to the file descriptor to access this chip.
|
|
|
|
# We may assume an i2c_set_slave_addr was already done.
|
|
|
|
# $_[2]: Address
|
1999-02-23 23:16:09 +00:00
|
|
|
# Returns: undef if not detected, (6) or (3) if detected.
|
1999-02-18 21:14:48 +00:00
|
|
|
# Registers used:
|
|
|
|
# 0xfe: Company ID
|
|
|
|
# 0x02: Status
|
|
|
|
# Note: Especially the Maxim has very bad detection; we give it a low
|
|
|
|
# confidence value.
|
|
|
|
sub adm1021_detect
|
|
|
|
{
|
|
|
|
my $reg;
|
|
|
|
my ($chip, $file,$addr) = @_;
|
|
|
|
return if $chip == 0 and i2c_smbus_read_byte_data($file,0xfe) != 0x41;
|
|
|
|
# The remaining things are flaky at best. Perhaps something can be done
|
|
|
|
# with the fact that some registers are unreadable?
|
1999-02-19 02:30:17 +00:00
|
|
|
return if (i2c_smbus_read_byte_data($file,0x02) & 0x03) != 0;
|
1999-02-18 21:14:48 +00:00
|
|
|
if ($chip == 0) {
|
|
|
|
return (6);
|
|
|
|
} else {
|
|
|
|
return (3);
|
|
|
|
}
|
|
|
|
}
|
1999-02-17 20:55:23 +00:00
|
|
|
|
1999-02-23 23:16:09 +00:00
|
|
|
# $_[0]: Address
|
|
|
|
# Returns: undef if not detected, (9) if detected.
|
|
|
|
# Note: It is already 99% certain this chip exists if we find the PCI
|
|
|
|
# entry. The exact address is encoded in PCI space.
|
|
|
|
sub sis5595_isa_detect
|
|
|
|
{
|
|
|
|
my ($addr) = @_;
|
1999-03-09 16:19:30 +00:00
|
|
|
my ($adapter,$try,$local_try);
|
1999-02-23 23:16:09 +00:00
|
|
|
my $found = 0;
|
1999-03-09 16:19:30 +00:00
|
|
|
foreach $local_try (@pci_adapters) {
|
|
|
|
if ($local_try->{procid} eq "Silicon Integrated Systems 85C503") {
|
|
|
|
$try = $local_try;
|
1999-02-23 23:16:09 +00:00
|
|
|
$found = 1;
|
|
|
|
last;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return if not $found;
|
|
|
|
|
|
|
|
$found = 0;
|
1999-02-24 01:12:05 +00:00
|
|
|
foreach $adapter (@pci_list) {
|
1999-03-09 16:19:30 +00:00
|
|
|
if ((defined($adapter->{vendid}) and
|
1999-02-23 23:16:09 +00:00
|
|
|
$try->{vendid} == $adapter->{vendid} and
|
|
|
|
$try->{devid} == $adapter->{devid} and
|
|
|
|
$try->{func} == $adapter->{func}) or
|
|
|
|
(! defined($adapter->{vendid}) and
|
|
|
|
$adapter->{desc} =~ /$try->{procid}/ and
|
|
|
|
$try->{func} == $adapter->{func})) {
|
|
|
|
$found = 1;
|
|
|
|
last;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return if not $found;
|
|
|
|
|
1999-03-09 16:19:30 +00:00
|
|
|
return 9;
|
|
|
|
}
|
|
|
|
|
|
|
|
# $_[0]: A reference to the file descriptor to access this chip.
|
|
|
|
# We may assume an i2c_set_slave_addr was already done.
|
|
|
|
# $_[1]: Address
|
|
|
|
# Returns: undef if not detected, (5) if detected.
|
|
|
|
# Registers used:
|
|
|
|
# 0x00-0x63: PC-100 Data and Checksum
|
|
|
|
sub eeprom_detect
|
|
|
|
{
|
|
|
|
my ($file,$addr) = @_;
|
|
|
|
# Check the checksum for validity (only works for PC-100 DIMMs)
|
|
|
|
my $checksum = 0;
|
|
|
|
for (my $i = 0; $i <= 62; $i = $i + 1) {
|
|
|
|
$checksum = $checksum + i2c_smbus_read_byte_data($file,$i);
|
|
|
|
}
|
|
|
|
$checksum=$checksum & 255;
|
|
|
|
if (i2c_smbus_read_byte_data($file,63) == $checksum) {
|
|
|
|
return (8);
|
|
|
|
}
|
|
|
|
# Even if checksum test fails, it still may be an eeprom
|
|
|
|
return (1);
|
1999-02-23 23:16:09 +00:00
|
|
|
}
|
|
|
|
|
1999-02-28 17:41:46 +00:00
|
|
|
################
|
|
|
|
# MAIN PROGRAM #
|
|
|
|
################
|
|
|
|
|
|
|
|
# $_[0]: reference to a list of chip hashes
|
|
|
|
sub print_chips_report
|
|
|
|
{
|
|
|
|
my ($listref) = @_;
|
|
|
|
my $data;
|
|
|
|
|
|
|
|
foreach $data (@$listref) {
|
|
|
|
my $is_i2c = exists $data->{i2c_addr};
|
|
|
|
my $is_isa = exists $data->{isa_addr};
|
|
|
|
print " * ";
|
|
|
|
if ($is_i2c) {
|
|
|
|
printf "Bus `%s' (%s)\n", $data->{i2c_adap}, $data->{i2c_algo};
|
|
|
|
printf " Busdriver `%s', I2C address 0x%02x",
|
|
|
|
$data->{i2c_driver}, $data->{i2c_addr};
|
|
|
|
if (exists $data->{i2c_sub_addrs}) {
|
|
|
|
print " (and";
|
|
|
|
my $sub_addr;
|
|
|
|
foreach $sub_addr (@{$data->{i2c_sub_addrs}}) {
|
|
|
|
printf " 0x%02x",$sub_addr;
|
|
|
|
}
|
|
|
|
print ")"
|
|
|
|
}
|
|
|
|
print "\n";
|
|
|
|
}
|
|
|
|
if ($is_isa) {
|
|
|
|
print " " if $is_i2c;
|
|
|
|
if ($data->{isa_addr}) {
|
|
|
|
printf "ISA bus address 0x%04x (Busdriver `i2c-isa')\n",
|
|
|
|
$data->{isa_addr};
|
|
|
|
} else {
|
|
|
|
printf "ISA bus, undetermined address (Busdriver `i2c-isa')\n"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
printf " Chip `%s' (confidence: %d)\n",
|
|
|
|
$data->{chipname}, $data->{conf};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-03-09 18:11:26 +00:00
|
|
|
# $_[0]: 1 if ISA bus is prefered, 0 for SMBus
|
1999-03-09 16:19:30 +00:00
|
|
|
sub generate_modprobes
|
1999-02-28 16:17:49 +00:00
|
|
|
{
|
1999-03-09 18:11:26 +00:00
|
|
|
my ($prefer_isa) = @_;
|
|
|
|
|
1999-03-23 21:48:41 +00:00
|
|
|
my ($chip,$detection,%adapters,$nr,$i,@optionlist,@probelist);
|
1999-03-09 16:19:30 +00:00
|
|
|
my $modprobes = "";
|
|
|
|
my $configfile = "";
|
|
|
|
|
|
|
|
# These are always needed
|
|
|
|
$modprobes .= "# General I2C modules\n";
|
|
|
|
$modprobes .= "modprobe i2c-proc\n";
|
|
|
|
$configfile .= "# I2C module options\n";
|
|
|
|
$configfile .= "alias char-major-89 i2c-dev\n";
|
|
|
|
|
|
|
|
# Collect all adapters
|
|
|
|
$nr = 0;
|
|
|
|
$modprobes .= "# I2C adapter drivers\n";
|
|
|
|
foreach $chip (@chips_detected) {
|
|
|
|
foreach $detection (@{$chip->{detected}}) {
|
|
|
|
%adapters->{$detection->{i2c_driver}} = $nr ++
|
|
|
|
if exists $detection->{i2c_driver} and
|
1999-03-09 18:11:26 +00:00
|
|
|
not exists %adapters->{$detection->{i2c_driver}} and
|
|
|
|
not (exists $detection->{isa_addr} and $prefer_isa);
|
1999-03-09 16:19:30 +00:00
|
|
|
%adapters->{"i2c-isa"} = $nr ++
|
|
|
|
if exists $detection->{isa_addr} and
|
1999-03-09 18:11:26 +00:00
|
|
|
not exists %adapters->{"i2c-isa"} and
|
|
|
|
not (exists $detection->{i2c_driver} and not $prefer_isa);
|
1999-03-09 16:19:30 +00:00
|
|
|
}
|
1999-02-28 17:24:41 +00:00
|
|
|
}
|
1999-03-10 20:31:58 +00:00
|
|
|
for ($i = 0; $i < $nr; $i ++) {
|
|
|
|
foreach $detection (keys %adapters) {
|
|
|
|
$modprobes .= "modprobe $detection\n", last
|
|
|
|
if $adapters{$detection} == $i;
|
|
|
|
}
|
1999-02-28 17:24:41 +00:00
|
|
|
}
|
|
|
|
|
1999-03-09 16:19:30 +00:00
|
|
|
# Now determine the chip probe lines
|
|
|
|
$modprobes .= "# I2C chip drivers\n";
|
|
|
|
foreach $chip (@chips_detected) {
|
|
|
|
next if not @{$chip->{detected}};
|
|
|
|
$modprobes .= "modprobe $chip->{driver}\n";
|
|
|
|
@optionlist = ();
|
1999-03-23 21:48:41 +00:00
|
|
|
@probelist = ();
|
|
|
|
|
|
|
|
# Handle detects out-of-range
|
|
|
|
foreach $detection (@{$chip->{detected}}) {
|
|
|
|
push @probelist, %adapters->{$detection->{i2c_driver}},
|
|
|
|
$detection->{i2c_addr}
|
|
|
|
if exists $detection->{i2c_driver} and
|
|
|
|
exists %adapters->{$detection->{i2c_driver}} and
|
|
|
|
exists $detection->{i2c_extra};
|
|
|
|
push @probelist, -1, $detection->{isa_addr}
|
|
|
|
if exists $detection->{isa_addr} and
|
|
|
|
exists %adapters->{"i2c-isa"} and
|
|
|
|
exists $detection->{isa_extra};
|
|
|
|
}
|
|
|
|
|
|
|
|
# Handle misdetects
|
1999-03-09 16:19:30 +00:00
|
|
|
foreach $detection (@{$chip->{misdetected}}) {
|
|
|
|
push @optionlist, %adapters->{$detection->{i2c_driver}},
|
|
|
|
$detection->{i2c_addr}
|
|
|
|
if exists $detection->{i2c_driver} and
|
|
|
|
exists %adapters->{$detection->{i2c_driver}};
|
|
|
|
push @optionlist, -1, $detection->{isa_addr}
|
|
|
|
if exists $detection->{isa_addr} and
|
|
|
|
exists %adapters->{"i2c-isa"};
|
|
|
|
}
|
1999-03-09 18:11:26 +00:00
|
|
|
|
|
|
|
# Handle aliases
|
|
|
|
foreach $detection (@{$chip->{detected}}) {
|
|
|
|
if (exists $detection->{i2c_driver} and
|
|
|
|
exists $detection->{isa_addr} and
|
|
|
|
exists %adapters->{$detection->{i2c_driver}} and
|
|
|
|
exists %adapters->{"i2c-isa"}) {
|
|
|
|
if ($prefer_isa) {
|
|
|
|
push @optionlist,%adapters->{$detection->{i2c_driver}},
|
|
|
|
$detection->{i2c_addr};
|
|
|
|
} else {
|
|
|
|
push @optionlist, -1, $detection->{isa_addr}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-03-23 21:48:41 +00:00
|
|
|
next if not (@probelist or @optionlist);
|
1999-03-09 16:19:30 +00:00
|
|
|
$configfile .= "options $chip->{driver}";
|
1999-03-23 21:48:41 +00:00
|
|
|
$configfile .= sprintf " ignore=%d,0x%02x",shift @optionlist,
|
|
|
|
shift @optionlist
|
|
|
|
if @optionlist;
|
|
|
|
$configfile .= sprintf ",%d,0x%02x",shift @optionlist, shift @optionlist
|
|
|
|
while @optionlist;
|
|
|
|
$configfile .= sprintf " probe=%d,0x%02x",shift @probelist,
|
|
|
|
shift @probelist
|
|
|
|
if @probelist;
|
|
|
|
$configfile .= sprintf ",%d,0x%02x",shift @probelist, shift @probelist
|
|
|
|
while @probelist;
|
1999-03-09 16:19:30 +00:00
|
|
|
$configfile .= "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
return ($modprobes,$configfile);
|
|
|
|
|
|
|
|
}
|
1999-02-17 20:55:23 +00:00
|
|
|
|
1999-02-19 01:52:29 +00:00
|
|
|
sub main
|
|
|
|
{
|
|
|
|
my (@adapters,$res,$did_adapter_detection,$detect_others,$adapter);
|
|
|
|
|
|
|
|
initialize_proc_pci;
|
|
|
|
initialize_modules_list;
|
|
|
|
|
|
|
|
print " This program will help you to determine which I2C/SMBus modules you ",
|
|
|
|
"need to\n",
|
|
|
|
" load to use lm_sensors most effectively.\n";
|
|
|
|
print " You need to have done a `make install', issued a `depmod -a' and ",
|
|
|
|
"made sure\n",
|
|
|
|
" `/etc/conf.modules' (or `/etc/modules.conf') contains the ",
|
|
|
|
"appropriate\n",
|
|
|
|
" module path before you can use some functions of this utility. ",
|
|
|
|
"Read\n",
|
|
|
|
" doc/modules for more information.\n";
|
|
|
|
print " Also, you need to be `root', or at least have access to the ",
|
|
|
|
"/dev/i2c-* files\n",
|
|
|
|
" for some things. You can use prog/mkdev/mkdev.sh to create these ",
|
|
|
|
"/dev files\n",
|
|
|
|
" if you do not have them already.\n\n";
|
|
|
|
|
|
|
|
print " We can start with probing for (PCI) I2C or SMBus adapters.\n";
|
|
|
|
print " You do not need any special privileges for this.\n";
|
|
|
|
print " Do you want to probe now? (YES/no): ";
|
|
|
|
@adapters = adapter_pci_detection
|
|
|
|
if ($did_adapter_detection = not <STDIN> =~ /\s*[Nn]/);
|
|
|
|
|
|
|
|
print "\n";
|
|
|
|
|
|
|
|
if (not $did_adapter_detection) {
|
|
|
|
print " As you skipped adapter detection, we will only scan already ",
|
|
|
|
"loaded adapter\n",
|
|
|
|
" modules. You can still be prompted for non-detectable adapters.\n",
|
|
|
|
" Do you want to? (yes/NO): ";
|
|
|
|
$detect_others = <STDIN> =~ /^\s*[Yy]/;
|
|
|
|
} elsif ($> != 0) {
|
|
|
|
print " As you are not root, we can't load adapter modules. We will only ",
|
|
|
|
"scan\n",
|
|
|
|
" already loaded adapters.\n";
|
|
|
|
$detect_others = 0;
|
|
|
|
} else {
|
|
|
|
print " We will now try to load each adapter module in turn.\n";
|
|
|
|
foreach $adapter (@adapters) {
|
|
|
|
if (contains $adapter, @modules_list) {
|
|
|
|
print "Module `$adapter' already loaded.\n";
|
|
|
|
} else {
|
|
|
|
print "Load `$adapter'? (YES/no): ";
|
|
|
|
unless (<STDIN> =~ /^\s*[Nn]/) {
|
|
|
|
if (system ("modprobe", $adapter)) {
|
|
|
|
print "Loading failed ($!)... skipping.\n";
|
|
|
|
} else {
|
|
|
|
print "Module loaded succesfully.\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
print " Do you now want to be prompted for non-detectable adapters? ",
|
1999-02-23 14:14:32 +00:00
|
|
|
"(yes/NO): ";
|
|
|
|
$detect_others = <STDIN> =~ /^\s*[Yy]/ ;
|
1999-02-19 01:52:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($detect_others) {
|
|
|
|
foreach $adapter (@undetectable_adapters) {
|
|
|
|
print "Load `$adapter'? (YES/no): ";
|
|
|
|
unless (<STDIN> =~ /^\s*[Nn]/) {
|
|
|
|
if (system ("modprobe", $adapter)) {
|
|
|
|
print "Loading failed ($!)... skipping.\n";
|
|
|
|
} else {
|
|
|
|
print "Module loaded succesfully.\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
print " To continue, we need modules `i2c-proc' and `i2c-dev' to be ",
|
|
|
|
"loaded.\n";
|
|
|
|
if (contains "i2c-proc", @modules_list) {
|
|
|
|
print "i2c-proc is already loaded.\n";
|
|
|
|
} else {
|
|
|
|
if ($> != 0) {
|
|
|
|
print " i2c-proc is not loaded, and you are not root. I can't ",
|
|
|
|
"continue.\n";
|
|
|
|
exit;
|
|
|
|
} else {
|
|
|
|
print " i2c-proc is not loaded. May I load it now? (YES/no): ";
|
|
|
|
if (<STDIN> =~ /^\s*[Nn]/) {
|
|
|
|
print " Sorry, in that case I can't continue.\n";
|
|
|
|
exit;
|
|
|
|
} elsif (system "modprobe","i2c-proc") {
|
|
|
|
print " Loading failed ($!), aborting.\n";
|
|
|
|
exit;
|
|
|
|
} else {
|
|
|
|
print " Module loaded succesfully.\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (contains "i2c-dev", @modules_list) {
|
|
|
|
print "i2c-dev is already loaded.\n";
|
|
|
|
} else {
|
|
|
|
if ($> != 0) {
|
|
|
|
print " i2c-dev is not loaded. As you are not root, we will just hope ",
|
|
|
|
"you edited\n",
|
|
|
|
" `/etc/conf.modules' (or `/etc/modules.conf') for automatic ",
|
|
|
|
"loading of\n",
|
|
|
|
" this module. If not, you won't be able to open any /dev/i2c-* ",
|
|
|
|
"file.\n";
|
|
|
|
} else {
|
|
|
|
print " i2c-dev is not loaded. Do you want to load it now? (YES/no): ";
|
|
|
|
if (<STDIN> =~ /^\s*[Nn]/) {
|
|
|
|
print " Well, you will know best. We will just hope you edited ",
|
|
|
|
"`/etc/conf.modules'\n",
|
|
|
|
" (or `/etc/modules.conf') for automatic loading of this ",
|
|
|
|
"module. If not,",
|
|
|
|
" you won't be able to open any /dev/i2c-* file.\n";
|
1999-02-19 18:11:03 +00:00
|
|
|
} elsif (system "modprobe","i2c-dev") {
|
1999-02-19 01:52:29 +00:00
|
|
|
print " Loading failed ($!), aborting.\n";
|
|
|
|
exit;
|
|
|
|
} else {
|
|
|
|
print " Module loaded succesfully.\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-02-23 14:14:32 +00:00
|
|
|
print "\n We are now going to do the adapter probings. Some adapters may ",
|
1999-02-19 01:52:29 +00:00
|
|
|
"hang halfway\n",
|
|
|
|
" through; we can't really help that. Also, some chips will be double ",
|
|
|
|
"detected;\n",
|
1999-02-24 00:22:52 +00:00
|
|
|
" choose the one with the highest confidence value in that case.\n",
|
|
|
|
" If you found that the adapter hung after probing a certain address, ",
|
|
|
|
"you can\n",
|
|
|
|
" specify that address to remain unprobed.\n";
|
1999-02-19 01:52:29 +00:00
|
|
|
|
1999-02-24 00:22:52 +00:00
|
|
|
my ($inp,@not_to_scan,$inp2);
|
1999-02-19 01:52:29 +00:00
|
|
|
open INPUTFILE,"/proc/bus/i2c" or die "Couldn't open /proc/bus/i2c?!?";
|
|
|
|
while (<INPUTFILE>) {
|
|
|
|
print "\n";
|
1999-02-23 14:14:32 +00:00
|
|
|
my ($dev_nr,$adap,$algo) = /^i2c-(\S+)\s+\S+\s+(.*?)\s*\t\s*(.*?)\s+$/;
|
|
|
|
print "Next adapter: $adap ($algo)\n";
|
1999-02-24 00:22:52 +00:00
|
|
|
print "Do you want to scan it? (YES/no/selectively): ";
|
|
|
|
|
|
|
|
$inp = <STDIN>;
|
|
|
|
@not_to_scan=();
|
|
|
|
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>;
|
|
|
|
chop $inp2;
|
|
|
|
@not_to_scan = parse_not_to_scan 0,0x7f,$inp2;
|
|
|
|
}
|
|
|
|
scan_adapter $dev_nr, $adap, $algo, find_adapter_driver($adap,$algo),
|
|
|
|
\@not_to_scan unless $inp =~ /^\s*[Nn]/;
|
1999-02-19 18:11:03 +00:00
|
|
|
}
|
|
|
|
|
1999-02-23 14:14:32 +00:00
|
|
|
print "\n Some chips are also accessible through the ISA bus. ISA probes ",
|
|
|
|
"are\n",
|
|
|
|
" typically a bit more dangerous, as we have to write to I/O ports ",
|
|
|
|
"to do\n",
|
|
|
|
" this. ";
|
|
|
|
if ($> != 0) {
|
|
|
|
print "As you are not root, we shall skip this step.\n";
|
|
|
|
} else {
|
|
|
|
print " Do you want to scan the ISA bus? (YES/no): ";
|
|
|
|
if (not <STDIN> =~ /^\s*[Nn]/) {
|
|
|
|
initialize_ioports or die "Sorry, can't access /dev/port ($!)?!?";
|
|
|
|
scan_isa_bus;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-02-19 18:11:03 +00:00
|
|
|
print "\n Now follows a summary of the probes I have just done.\n";
|
1999-03-09 18:11:26 +00:00
|
|
|
print " Just press ENTER to continue: ";
|
|
|
|
<STDIN>;
|
|
|
|
|
1999-02-19 18:11:03 +00:00
|
|
|
my ($chip,$data);
|
|
|
|
foreach $chip (@chips_detected) {
|
|
|
|
print "\nDriver `$$chip{driver}' ";
|
|
|
|
if (@{$$chip{detected}}) {
|
|
|
|
if (@{$$chip{misdetected}}) {
|
|
|
|
print "(should be inserted but causes problems):\n";
|
|
|
|
} else {
|
|
|
|
print "(should be inserted):\n";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (@{$$chip{misdetected}}) {
|
|
|
|
print "(may not be inserted):\n";
|
|
|
|
} else {
|
|
|
|
print "(should not be inserted, but is harmless):\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (@{$$chip{detected}}) {
|
1999-02-19 18:12:27 +00:00
|
|
|
print " Detects correctly:\n";
|
1999-02-28 17:41:46 +00:00
|
|
|
print_chips_report $chip->{detected};
|
1999-02-19 18:11:03 +00:00
|
|
|
}
|
|
|
|
if (@{$$chip{misdetected}}) {
|
|
|
|
print " Misdetects:\n";
|
1999-02-28 17:41:46 +00:00
|
|
|
print_chips_report $chip->{misdetected};
|
1999-02-19 18:11:03 +00:00
|
|
|
}
|
1999-02-19 01:52:29 +00:00
|
|
|
}
|
1999-03-09 16:19:30 +00:00
|
|
|
|
1999-03-09 18:11:26 +00:00
|
|
|
print "\n\n",
|
|
|
|
" I will now generate the commands needed to load the I2C modules.\n",
|
|
|
|
" Sometimes, a chip is available both through the ISA bus and an ",
|
|
|
|
"I2C bus.\n",
|
|
|
|
" ISA bus access is faster, but you need to load an additional driver ",
|
|
|
|
"module\n",
|
|
|
|
" for it. If you have the choice, do you want to use the ISA bus or ",
|
|
|
|
"the\n",
|
|
|
|
" I2C/SMBus (ISA/smbus)? ";
|
|
|
|
my $use_isa = not <STDIN> =~ /\s*[Ss]/;
|
|
|
|
|
|
|
|
my ($modprobes,$configfile) = generate_modprobes $use_isa;
|
|
|
|
print "\nTo load everything that is needed, add this to some /etc/rc* ",
|
1999-03-09 16:19:30 +00:00
|
|
|
"file:\n\n";
|
|
|
|
print "#----cut here----\n";
|
|
|
|
print $modprobes;
|
|
|
|
print "#----cut here----\n";
|
|
|
|
print "\nTo make the sensors modules behave correctly, add these lines to ",
|
|
|
|
"either\n",
|
|
|
|
"/etc/modules.conf or /etc/conf.modules:\n\n";
|
|
|
|
print "#----cut here----\n";
|
|
|
|
print $configfile;
|
|
|
|
print "#----cut here----\n";
|
|
|
|
|
1999-02-19 01:52:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
main;
|