2
0
mirror of https://github.com/lm-sensors/lm-sensors synced 2025-08-31 06:15:15 +00:00

ISA detection is completed for LM7x and W8378xx

No alias detection (ie. detection of chips connected to both ISA and I2C bus)
is done yet; but all hooks are in.


git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@265 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
Frodo Looijaard
1999-02-23 14:14:32 +00:00
parent 0411f7810c
commit cfece5dd19
2 changed files with 354 additions and 136 deletions

View File

@@ -41,7 +41,7 @@ use vars qw(@pci_adapters @chip_ids @undetectable_adapters);
# 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
# driver (Driver Name) field. The match (Match Description) field should
# contain a function which returns zero if its first parameter matches
# contain a function which returns zero if its two parameter matches
# the text as it would appear in /proc/bus/i2c.
@pci_adapters = (
{
@@ -91,29 +91,35 @@ use subs qw(lm78_detect lm78_isa_detect lm75_detect lm80_detect w83781d_detect
# 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.
# isa_addrs (optional): For ISA chips, the range of valid port addresses to
# probe.
# isa_detect (optional): For ISA chips, the function to call to detect
# this chip. The function should take no parameters.
# this chip. The function should take one parameter: the ISA address
# to probe.
@chip_ids = (
{
name => "National Semiconductors LM78",
driver => "lm78",
i2c_addrs => [0x00..0x7f],
i2c_detect => sub { lm78_detect 0, @_},
isa_detect => sub { lm78_isa_detect 0 },
isa_addrs => [0x290],
isa_detect => sub { lm78_isa_detect 0, @_ },
} ,
{
name => "National Semiconductors LM78-J",
driver => "lm78",
i2c_addrs => [0x00..0x7f],
i2c_detect => sub { lm78_detect 1, @_ },
isa_detect => sub { lm78_isa_detect 1 },
isa_addrs => [0x290],
isa_detect => sub { lm78_isa_detect 1, @_ },
} ,
{
name => "National Semiconductors LM79",
driver => "lm78",
i2c_addrs => [0x00..0x7f],
i2c_detect => sub { lm78_detect 2, @_ },
isa_detect => sub { lm78_isa_detect 2 },
isa_addrs => [0x290],
isa_detect => sub { lm78_isa_detect 2, @_ },
} ,
{
name => "National Semiconductors LM75",
@@ -132,21 +138,24 @@ use subs qw(lm78_detect lm78_isa_detect lm75_detect lm80_detect w83781d_detect
driver => "w83781d",
i2c_addrs => [0x00..0x7f],
i2c_detect => sub { w83781d_detect 0, @_},
isa_detect => sub { w83781d_isa_detect 0 },
isa_addrs => [0x290],
isa_detect => sub { w83781d_isa_detect 0, @_ },
} ,
{
name => "Winbond W83782D",
driver => "w83781d",
i2c_addrs => [0x00..0x7f],
i2c_detect => sub { w83781d_detect 1, @_},
isa_detect => sub { w83781d_isa_detect 1 },
isa_addrs => [0x290],
isa_detect => sub { w83781d_isa_detect 1, @_ },
} ,
{
name => "Winbond W83783S",
driver => "w83781d",
i2c_addrs => [0x00..0x7f],
i2c_detect => sub { w83781d_detect 2, @_},
isa_detect => sub { w83781d_isa_detect 2 },
isa_addrs => [0x290],
isa_detect => sub { w83781d_isa_detect 2, @_ },
} ,
{
name => "Genesys Logic GL518SM Revision 0x00",
@@ -212,7 +221,7 @@ sub contains
# I/O port access #
###################
sub initialize_io
sub initialize_ioports
{
sysopen IOPORTS, "/dev/port", 2;
}
@@ -392,12 +401,13 @@ sub adapter_pci_detection
return @res;
}
# $_[0]: Description as found in /proc/bus/i2c
# $_[0]: Adapter description as found in /proc/bus/i2c
# $_[1]: Algorithm description as found in /proc/bus/i2c
sub find_adapter_driver
{
my $adapter;
for $adapter (@pci_adapters) {
return $adapter->{driver} if &{$adapter->{match}} ($_[0]);
return $adapter->{driver} if &{$adapter->{match}} ($_[0],$_[1]);
}
return "?????";
}
@@ -624,7 +634,9 @@ use vars qw(@chips_detected);
# with field 'detected'
# being a reference to a list of
# references to hashes
# with field 'description' containing an adapter string as appearing
# with field 'adap' containing an adapter string as appearing
# in /proc/bus/i2c
# with field 'algo' containing an algorithm string as appearing
# in /proc/bus/i2c
# with field 'driver', containing the driver name for this adapter;
# with field 'address', containing the I2C address of the detection;
@@ -636,12 +648,15 @@ use vars qw(@chips_detected);
# Winbond chips)
# with optional field 'isa_addr' containing the ISA address this
# chip is on (for aliased chips, also the other fields are
# present; else 'driver' and 'address' are no present)
# present; else 'driver', 'address', 'algo' and 'adap' are not
# present)
#
# with field 'misdetected'
# being a reference to a list of
# references to hashes
# with field 'description' containing an adapter string as appearing
# with field 'adap' containing an adapter string as appearing
# in /proc/bus/i2c
# with field 'algo' containing an algorithm string as appearing
# in /proc/bus/i2c
# with field 'driver', containing the driver name for this adapter;
# with field 'address', containing the I2C address of the detection;
@@ -653,15 +668,16 @@ use vars qw(@chips_detected);
# Winbond chips)
# with optional field 'isa_addr' containing the ISA address this
# chip is on (for aliased chips, also the other fields are
# present; else 'driver' and 'address' are no present)
# present; else 'driver', 'address', 'algo' and 'adap' are not
# present)
# $_[0]: chip driver
# $_[1]: reference to data hash
sub add_to_chips_detected
{
my ($chipdriver,$datahash,$detected_ref,$misdetected_ref,
$new_detected_ref,$new_misdetected_ref) = @_;
my ($i,$j,$found_it);
my ($chipdriver,$datahash) = @_;
my ($detected_ref,$misdetected_ref, $new_detected_ref,$new_misdetected_ref,
$i,$j,$found_it);
for ($i = 0; $i < @chips_detected; $i++) {
last if ($chips_detected[$i]->{driver} eq $chipdriver);
}
@@ -689,7 +705,8 @@ sub add_to_chips_detected
$misdetected_ref = $chips_detected[$i]->{misdetected};
for ($j = 0; $j < @$detected_ref ; $j++) {
if ($detected_ref->[$j]->{driver} eq $datahash->{driver} and
$detected_ref->[$j]->{description} eq $datahash->{description} and
$detected_ref->[$j]->{adap} eq $datahash->{adap} and
$detected_ref->[$j]->{algo} eq $datahash->{algo} and
$detected_ref->[$j]->{address} eq $datahash->{address}) {
if ($detected_ref->[$j]->{confidence} < $datahash->{confidence}) {
push @$misdetected_ref, $detected_ref->[$j];
@@ -708,12 +725,62 @@ sub add_to_chips_detected
push @$new_detected_ref, $datahash if not $found_it
}
sub add_isa_to_chips_detected
{
my ($chipdriver,$datahash) = @_;
my ($detected_ref,$misdetected_ref, $new_detected_ref,$new_misdetected_ref,
$i,$j,$found_it);
# First locate this chip driver's location in the big structure, or
# create it */
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};
# Now, we are looking for aliases. To be done.
# If an alias is found, it is removed from the structure, and the data
# is put in %$datahash. If not, nothing happens
# At long last, we will insert the new reference, looking out whether
# some other chip has already claimed this ISA address.
$found_it = 0;
LOOP: for ($i = 0; $i < @chips_detected; $i++) {
$detected_ref = $chips_detected[$i]->{detected};
$misdetected_ref = $chips_detected[$i]->{misdetected};
for ($j = 0; $j < @$detected_ref ; $j++) {
if (exists $detected_ref->[$j]->{isa_addr} and
$detected_ref->[$j]->{isa_addr} == $datahash->{isa_addr}) {
if ($detected_ref->[$j]->{confidence} < $datahash->{confidence}) {
push @$misdetected_ref, $detected_ref->[$j];
splice @$detected_ref, $j, 1;
push @$new_detected_ref, $datahash;
$found_it = 1;
last LOOP;
} else {
push @$new_misdetected_ref, $datahash;
$found_it = 1;
last LOOP;
}
}
}
}
push @$new_detected_ref, $datahash if not $found_it
}
# $_[0]: The number of the adapter to scan
# $_[1]: The name of the adapter, as appearing in /proc/bus/i2c
# $_[2]: The driver of the adapter
# $_[2]: The name of the algorithm, as appearing in /proc/bus/i2c
# $_[3]: The driver of the adapter
sub scan_adapter
{
my ( $adapter_nr,$adapter_name,$adapter_driver) = @_;
my ( $adapter_nr,$adapter_name,$algorithm_name,$adapter_driver) = @_;
my ($chip, $addr, $conf,@chips,$add_addr);
open FILE,"/dev/i2c-$adapter_nr" or
print ("Can't open /dev/i2c-$adapter_nr ($!)\n"), return;
@@ -737,7 +804,8 @@ sub scan_adapter
{ confidence => $conf,
address => $addr,
chipname => $$chip{name},
description => $adapter_name,
adapter => $adapter_name,
algorithm => $algorithm_name,
driver => $adapter_driver,
};
foreach $add_addr(@chips) {
@@ -745,7 +813,8 @@ sub scan_adapter
{ confidence => $conf,
address => $add_addr,
chipname => $$chip{name},
description => $adapter_name,
adapter => $adapter_name,
algorithm => $algorithm_name,
driver => $adapter_driver,
main => $addr,
};
@@ -758,6 +827,27 @@ sub scan_adapter
}
}
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};
print "Probing for `$$chip{name}\n";
foreach $addr (@{$$chip{isa_addrs}}) {
printf " Trying address 0x%04x... ", $addr;
$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};
add_isa_to_chips_detected $$chip{driver},
{ confidence => $conf,
isa_addr => $addr,
chipname => $$chip{name},
};
}
}
}
##################
# CHIP DETECTION #
@@ -803,23 +893,22 @@ sub lm78_detect
}
# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
# $_[1]: Address
# Returns: undef if not detected, (7) if detected.
# Note: Only address 0x290 is scanned at this moment.
sub lm78_isa_detect
{
my ($chip) = @_ ;
my $addr;
foreach $addr (0x290) {
my $val = inb ($addr + 1);
next if inb ($addr + 2) != $val or inb ($addr + 3) != $val or
my ($chip,$addr) = @_ ;
my $val = inb ($addr + 1);
return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or
inb ($addr + 7) != $val;
my $readproc = sub { isa_read_addr ($addr + 5, $addr + 6) };
next unless (&$readproc(0x40) & 0x80) == 0x00;
my $reg = &$readproc($0x49);
next unless ($chip == 0 and $reg == 0x00) or
($chip == 1 and $reg == 0x40) or
($chip == 2 and ($reg & 0xfe) == 0xc0);
}
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;
}
# $_[0]: A reference to the file descriptor to access this chip.
@@ -909,27 +998,25 @@ sub w83781d_detect
}
# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 3 = W83783S)
# $_[1]: Address
# Returns: undef if not detected, (8) if detected.
# Note: Only address 0x290 is scanned at this moment.
sub w83781d_isa_detect
{
my ($chip) = @_ ;
my ($addr,$reg1,$reg2);
foreach $addr (0x290) {
my $val = inb ($addr + 1);
next if inb ($addr + 2) != $val or inb ($addr + 3) != $val or
my ($chip,$addr) = @_ ;
my ($reg1,$reg2);
my $val = inb ($addr + 1);
return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or
inb ($addr + 7) != $val;
my $read_proc = sub { isa_read_addr ($addr + 5, $addr + 6) };
$reg1 = &$read_proc(0x4e);
$reg2 = &$read_proc(0x4f);
next unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or
(($reg1 & 0x80) == 0x80 and $reg2 == 0x5c);
next unless ($reg1 & 0x07) == 0x00;
$reg1 = &$read_proc(0x58);
next if $chip == 0 and ($reg1 & 0xfe) != 0x10;
next if $chip == 1 and $reg1 != 0x30;
next if $chip == 2 and $reg1 != 0x40;
}
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;
$reg1 = &$read_proc(0x58);
return if $chip == 0 and ($reg1 & 0xfe) != 0x10;
return if $chip == 1 and $reg1 != 0x30;
return if $chip == 2 and $reg1 != 0x40;
}
# $_[0]: Chip to detect (0 = Revision 0x00, 1 = Revision 0x80)
@@ -1080,8 +1167,8 @@ sub main
}
}
print " Do you now want to be prompted for non-detectable adapters? ",
"(YES/no): ";
$detect_others = not <STDIN> =~ /^\s*[Nn]/ ;
"(yes/NO): ";
$detect_others = <STDIN> =~ /^\s*[Yy]/ ;
}
if ($detect_others) {
@@ -1146,7 +1233,7 @@ sub main
}
}
print " \n We are now going to do the adapter probings. Some adapters may ",
print "\n We are now going to do the adapter probings. Some adapters may ",
"hang halfway\n",
" through; we can't really help that. Also, some chips will be double ",
"detected;\n",
@@ -1155,14 +1242,28 @@ sub main
open INPUTFILE,"/proc/bus/i2c" or die "Couldn't open /proc/bus/i2c?!?";
while (<INPUTFILE>) {
print "\n";
my ($dev_nr,$description) = /^i2c-(\S+)\s+\S+\s+(.*)$/;
$description =~ s/\t/ /;
print "Next adapter: $description\n";
my ($dev_nr,$adap,$algo) = /^i2c-(\S+)\s+\S+\s+(.*?)\s*\t\s*(.*?)\s+$/;
print "Next adapter: $adap ($algo)\n";
print "Do you want to scan it? (YES/no): ";
scan_adapter $dev_nr, $description, find_adapter_driver($description)
scan_adapter $dev_nr, $adap, $algo, find_adapter_driver($adap,$algo)
unless <STDIN> =~ /^\s*[Nn]/;
}
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;
}
}
print "\n Now follows a summary of the probes I have just done.\n";
my ($chip,$data);
foreach $chip (@chips_detected) {
@@ -1183,21 +1284,29 @@ sub main
if (@{$$chip{detected}}) {
print " Detects correctly:\n";
foreach $data (@{$$chip{detected}}) {
printf " * Bus `%s'\n".
" Busdriver `%s', I2C address 0x%02x\n".
" Chip `%s' (confidence: %d)\n",
$data->{description}, $data->{driver}, $data->{address},
my $is_i2c = exists $data->{address};
my $is_isa = exists $data->{isa_addr};
print " * ";
printf "Bus `%s' (%s)\n", $data->{adapter}, $data->{algorithm}
if $is_i2c;
printf " Busdriver `%s', I2C address 0x%02x", $data->{driver},
$data->{address} if $is_i2c;
printf "(main: 0x%02x", $data->{main} if (exists $data->{main});
print " " if $is_i2c and $is_isa;
printf "ISA bus address 0x%04x", $data->{isa_addr} if $is_isa;
printf "\n Chip `%s' (confidence: %d)\n",
$data->{chipname}, $data->{confidence};
}
}
if (@{$$chip{misdetected}}) {
print " Misdetects:\n";
foreach $data (@{$$chip{misdetected}}) {
printf " * Bus: %s\n".
" Busdriver `%s', I2C address 0x%02x\n".
" Chip `%s' (confidence: %d)\n",
$data->{description}, $data->{driver}, $data->{address},
$data->{chipname}, $data->{confidence};
printf " * Bus `%s' (%s)\n", $data->{adapter}, $data->{algorithm};
printf " Busdriver `%s', I2C address 0x%02x", $data->{driver},
$data->{address};
printf "(main: 0x%02x", $data->{main} if (exists $data->{main});
printf "\n Chip `%s' (confidence: %d)\n",
$data->{chipname}, $data->{confidence};
}
}
}