2
0
mirror of https://github.com/lm-sensors/lm-sensors synced 2025-09-04 00:05:10 +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, # 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 # either pci.c or oldproc.c). If no driver is written yet, omit the
# driver (Driver Name) field. The match (Match Description) field should # 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. # the text as it would appear in /proc/bus/i2c.
@pci_adapters = ( @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 # i2c_detect (optional): For I2C chips, the function to call to detect
# this chip. The function should take two parameters: an open file # this chip. The function should take two parameters: an open file
# descriptor to access the bus, and the I2C address to probe. # 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 # 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 = ( @chip_ids = (
{ {
name => "National Semiconductors LM78", name => "National Semiconductors LM78",
driver => "lm78", driver => "lm78",
i2c_addrs => [0x00..0x7f], i2c_addrs => [0x00..0x7f],
i2c_detect => sub { lm78_detect 0, @_}, 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", name => "National Semiconductors LM78-J",
driver => "lm78", driver => "lm78",
i2c_addrs => [0x00..0x7f], i2c_addrs => [0x00..0x7f],
i2c_detect => sub { lm78_detect 1, @_ }, 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", name => "National Semiconductors LM79",
driver => "lm78", driver => "lm78",
i2c_addrs => [0x00..0x7f], i2c_addrs => [0x00..0x7f],
i2c_detect => sub { lm78_detect 2, @_ }, 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", name => "National Semiconductors LM75",
@@ -132,21 +138,24 @@ use subs qw(lm78_detect lm78_isa_detect lm75_detect lm80_detect w83781d_detect
driver => "w83781d", driver => "w83781d",
i2c_addrs => [0x00..0x7f], i2c_addrs => [0x00..0x7f],
i2c_detect => sub { w83781d_detect 0, @_}, 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", name => "Winbond W83782D",
driver => "w83781d", driver => "w83781d",
i2c_addrs => [0x00..0x7f], i2c_addrs => [0x00..0x7f],
i2c_detect => sub { w83781d_detect 1, @_}, 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", name => "Winbond W83783S",
driver => "w83781d", driver => "w83781d",
i2c_addrs => [0x00..0x7f], i2c_addrs => [0x00..0x7f],
i2c_detect => sub { w83781d_detect 2, @_}, 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", name => "Genesys Logic GL518SM Revision 0x00",
@@ -212,7 +221,7 @@ sub contains
# I/O port access # # I/O port access #
################### ###################
sub initialize_io sub initialize_ioports
{ {
sysopen IOPORTS, "/dev/port", 2; sysopen IOPORTS, "/dev/port", 2;
} }
@@ -392,12 +401,13 @@ sub adapter_pci_detection
return @res; 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 sub find_adapter_driver
{ {
my $adapter; my $adapter;
for $adapter (@pci_adapters) { for $adapter (@pci_adapters) {
return $adapter->{driver} if &{$adapter->{match}} ($_[0]); return $adapter->{driver} if &{$adapter->{match}} ($_[0],$_[1]);
} }
return "?????"; return "?????";
} }
@@ -624,7 +634,9 @@ use vars qw(@chips_detected);
# with field 'detected' # with field 'detected'
# being a reference to a list of # being a reference to a list of
# references to hashes # 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 # in /proc/bus/i2c
# with field 'driver', containing the driver name for this adapter; # with field 'driver', containing the driver name for this adapter;
# with field 'address', containing the I2C address of the detection; # with field 'address', containing the I2C address of the detection;
@@ -636,12 +648,15 @@ use vars qw(@chips_detected);
# Winbond chips) # Winbond chips)
# with optional field 'isa_addr' containing the ISA address this # with optional field 'isa_addr' containing the ISA address this
# chip is on (for aliased chips, also the other fields are # 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' # with field 'misdetected'
# being a reference to a list of # being a reference to a list of
# references to hashes # 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 # in /proc/bus/i2c
# with field 'driver', containing the driver name for this adapter; # with field 'driver', containing the driver name for this adapter;
# with field 'address', containing the I2C address of the detection; # with field 'address', containing the I2C address of the detection;
@@ -653,15 +668,16 @@ use vars qw(@chips_detected);
# Winbond chips) # Winbond chips)
# with optional field 'isa_addr' containing the ISA address this # with optional field 'isa_addr' containing the ISA address this
# chip is on (for aliased chips, also the other fields are # 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 # $_[0]: chip driver
# $_[1]: reference to data hash # $_[1]: reference to data hash
sub add_to_chips_detected sub add_to_chips_detected
{ {
my ($chipdriver,$datahash,$detected_ref,$misdetected_ref, my ($chipdriver,$datahash) = @_;
$new_detected_ref,$new_misdetected_ref) = @_; my ($detected_ref,$misdetected_ref, $new_detected_ref,$new_misdetected_ref,
my ($i,$j,$found_it); $i,$j,$found_it);
for ($i = 0; $i < @chips_detected; $i++) { for ($i = 0; $i < @chips_detected; $i++) {
last if ($chips_detected[$i]->{driver} eq $chipdriver); last if ($chips_detected[$i]->{driver} eq $chipdriver);
} }
@@ -689,7 +705,8 @@ sub add_to_chips_detected
$misdetected_ref = $chips_detected[$i]->{misdetected}; $misdetected_ref = $chips_detected[$i]->{misdetected};
for ($j = 0; $j < @$detected_ref ; $j++) { for ($j = 0; $j < @$detected_ref ; $j++) {
if ($detected_ref->[$j]->{driver} eq $datahash->{driver} and 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}) { $detected_ref->[$j]->{address} eq $datahash->{address}) {
if ($detected_ref->[$j]->{confidence} < $datahash->{confidence}) { if ($detected_ref->[$j]->{confidence} < $datahash->{confidence}) {
push @$misdetected_ref, $detected_ref->[$j]; push @$misdetected_ref, $detected_ref->[$j];
@@ -708,12 +725,62 @@ sub add_to_chips_detected
push @$new_detected_ref, $datahash if not $found_it 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 # $_[0]: The number of the adapter to scan
# $_[1]: The name of the adapter, as appearing in /proc/bus/i2c # $_[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 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); my ($chip, $addr, $conf,@chips,$add_addr);
open FILE,"/dev/i2c-$adapter_nr" or open FILE,"/dev/i2c-$adapter_nr" or
print ("Can't open /dev/i2c-$adapter_nr ($!)\n"), return; print ("Can't open /dev/i2c-$adapter_nr ($!)\n"), return;
@@ -737,7 +804,8 @@ sub scan_adapter
{ confidence => $conf, { confidence => $conf,
address => $addr, address => $addr,
chipname => $$chip{name}, chipname => $$chip{name},
description => $adapter_name, adapter => $adapter_name,
algorithm => $algorithm_name,
driver => $adapter_driver, driver => $adapter_driver,
}; };
foreach $add_addr(@chips) { foreach $add_addr(@chips) {
@@ -745,7 +813,8 @@ sub scan_adapter
{ confidence => $conf, { confidence => $conf,
address => $add_addr, address => $add_addr,
chipname => $$chip{name}, chipname => $$chip{name},
description => $adapter_name, adapter => $adapter_name,
algorithm => $algorithm_name,
driver => $adapter_driver, driver => $adapter_driver,
main => $addr, 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 # # CHIP DETECTION #
@@ -803,23 +893,22 @@ sub lm78_detect
} }
# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79) # $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
# $_[1]: Address
# Returns: undef if not detected, (7) if detected. # Returns: undef if not detected, (7) if detected.
# Note: Only address 0x290 is scanned at this moment. # Note: Only address 0x290 is scanned at this moment.
sub lm78_isa_detect sub lm78_isa_detect
{ {
my ($chip) = @_ ; my ($chip,$addr) = @_ ;
my $addr; my $val = inb ($addr + 1);
foreach $addr (0x290) { return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or
my $val = inb ($addr + 1);
next if inb ($addr + 2) != $val or inb ($addr + 3) != $val or
inb ($addr + 7) != $val; inb ($addr + 7) != $val;
my $readproc = sub { isa_read_addr ($addr + 5, $addr + 6) }; my $readproc = sub { isa_read_byte $addr + 5, $addr + 6, @_ };
next unless (&$readproc(0x40) & 0x80) == 0x00; return unless (&$readproc(0x40) & 0x80) == 0x00;
my $reg = &$readproc($0x49); my $reg = &$readproc(0x49);
next unless ($chip == 0 and $reg == 0x00) or return unless ($chip == 0 and $reg == 0x00) or
($chip == 1 and $reg == 0x40) or ($chip == 1 and $reg == 0x40) or
($chip == 2 and ($reg & 0xfe) == 0xc0); ($chip == 2 and ($reg & 0xfe) == 0xc0);
} return 7;
} }
# $_[0]: A reference to the file descriptor to access this chip. # $_[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) # $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 3 = W83783S)
# $_[1]: Address
# Returns: undef if not detected, (8) if detected. # Returns: undef if not detected, (8) if detected.
# Note: Only address 0x290 is scanned at this moment.
sub w83781d_isa_detect sub w83781d_isa_detect
{ {
my ($chip) = @_ ; my ($chip,$addr) = @_ ;
my ($addr,$reg1,$reg2); my ($reg1,$reg2);
foreach $addr (0x290) { my $val = inb ($addr + 1);
my $val = inb ($addr + 1); return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or
next if inb ($addr + 2) != $val or inb ($addr + 3) != $val or
inb ($addr + 7) != $val; inb ($addr + 7) != $val;
my $read_proc = sub { isa_read_addr ($addr + 5, $addr + 6) }; my $read_proc = sub { isa_read_byte $addr + 5, $addr + 6, @_ };
$reg1 = &$read_proc(0x4e); $reg1 = &$read_proc(0x4e);
$reg2 = &$read_proc(0x4f); $reg2 = &$read_proc(0x4f);
next unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or
(($reg1 & 0x80) == 0x80 and $reg2 == 0x5c); (($reg1 & 0x80) == 0x80 and $reg2 == 0x5c);
next unless ($reg1 & 0x07) == 0x00; return unless ($reg1 & 0x07) == 0x00;
$reg1 = &$read_proc(0x58); $reg1 = &$read_proc(0x58);
next if $chip == 0 and ($reg1 & 0xfe) != 0x10; return if $chip == 0 and ($reg1 & 0xfe) != 0x10;
next if $chip == 1 and $reg1 != 0x30; return if $chip == 1 and $reg1 != 0x30;
next if $chip == 2 and $reg1 != 0x40; return if $chip == 2 and $reg1 != 0x40;
}
} }
# $_[0]: Chip to detect (0 = Revision 0x00, 1 = Revision 0x80) # $_[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? ", print " Do you now want to be prompted for non-detectable adapters? ",
"(YES/no): "; "(yes/NO): ";
$detect_others = not <STDIN> =~ /^\s*[Nn]/ ; $detect_others = <STDIN> =~ /^\s*[Yy]/ ;
} }
if ($detect_others) { 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", "hang halfway\n",
" through; we can't really help that. Also, some chips will be double ", " through; we can't really help that. Also, some chips will be double ",
"detected;\n", "detected;\n",
@@ -1155,14 +1242,28 @@ sub main
open INPUTFILE,"/proc/bus/i2c" or die "Couldn't open /proc/bus/i2c?!?"; open INPUTFILE,"/proc/bus/i2c" or die "Couldn't open /proc/bus/i2c?!?";
while (<INPUTFILE>) { while (<INPUTFILE>) {
print "\n"; print "\n";
my ($dev_nr,$description) = /^i2c-(\S+)\s+\S+\s+(.*)$/; my ($dev_nr,$adap,$algo) = /^i2c-(\S+)\s+\S+\s+(.*?)\s*\t\s*(.*?)\s+$/;
$description =~ s/\t/ /; print "Next adapter: $adap ($algo)\n";
print "Next adapter: $description\n";
print "Do you want to scan it? (YES/no): "; 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]/; 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"; print "\n Now follows a summary of the probes I have just done.\n";
my ($chip,$data); my ($chip,$data);
foreach $chip (@chips_detected) { foreach $chip (@chips_detected) {
@@ -1183,21 +1284,29 @@ sub main
if (@{$$chip{detected}}) { if (@{$$chip{detected}}) {
print " Detects correctly:\n"; print " Detects correctly:\n";
foreach $data (@{$$chip{detected}}) { foreach $data (@{$$chip{detected}}) {
printf " * Bus `%s'\n". my $is_i2c = exists $data->{address};
" Busdriver `%s', I2C address 0x%02x\n". my $is_isa = exists $data->{isa_addr};
" Chip `%s' (confidence: %d)\n", print " * ";
$data->{description}, $data->{driver}, $data->{address}, 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}; $data->{chipname}, $data->{confidence};
} }
} }
if (@{$$chip{misdetected}}) { if (@{$$chip{misdetected}}) {
print " Misdetects:\n"; print " Misdetects:\n";
foreach $data (@{$$chip{misdetected}}) { foreach $data (@{$$chip{misdetected}}) {
printf " * Bus: %s\n". printf " * Bus `%s' (%s)\n", $data->{adapter}, $data->{algorithm};
" Busdriver `%s', I2C address 0x%02x\n". printf " Busdriver `%s', I2C address 0x%02x", $data->{driver},
" Chip `%s' (confidence: %d)\n", $data->{address};
$data->{description}, $data->{driver}, $data->{address}, printf "(main: 0x%02x", $data->{main} if (exists $data->{main});
$data->{chipname}, $data->{confidence}; printf "\n Chip `%s' (confidence: %d)\n",
$data->{chipname}, $data->{confidence};
} }
} }
} }

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