mirror of
https://github.com/lm-sensors/lm-sensors
synced 2025-09-05 08:45:26 +00:00
sensors-detect: Check i2c adapter functionalities before probing, so that
we don't use SMBus transactions the adapter doesn't support. This could be extended to the transactions used during detection itself. git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@4086 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
@@ -2437,6 +2437,7 @@ sub find_adapter_driver
|
||||
# These are copied from <linux/i2c-dev.h>
|
||||
|
||||
use constant IOCTL_I2C_SLAVE => 0x0703;
|
||||
use constant IOCTL_I2C_FUNCS => 0x0705;
|
||||
use constant IOCTL_I2C_SMBUS => 0x0720;
|
||||
|
||||
use constant SMBUS_READ => 1;
|
||||
@@ -2447,6 +2448,23 @@ use constant SMBUS_BYTE => 1;
|
||||
use constant SMBUS_BYTE_DATA => 2;
|
||||
use constant SMBUS_WORD_DATA => 3;
|
||||
|
||||
use constant I2C_FUNC_SMBUS_QUICK => 0x00010000;
|
||||
use constant I2C_FUNC_SMBUS_READ_BYTE => 0x00020000;
|
||||
|
||||
# Get the i2c adapter's functionalities
|
||||
# $_[0]: Reference to an opened filehandle
|
||||
# Returns: -1 on failure, functionality bitfield on success.
|
||||
sub i2c_get_funcs($)
|
||||
{
|
||||
my $file = shift;
|
||||
my $funcs;
|
||||
|
||||
ioctl $file, IOCTL_I2C_FUNCS, $funcs='' or return -1;
|
||||
$funcs = unpack "L", $funcs;
|
||||
|
||||
return $funcs;
|
||||
}
|
||||
|
||||
# Select the device to communicate with through its address.
|
||||
# $_[0]: Reference to an opened filehandle
|
||||
# $_[1]: Address to select
|
||||
@@ -2532,13 +2550,14 @@ sub i2c_smbus_read_word_data
|
||||
|
||||
# $_[0]: Reference to an opened filehandle
|
||||
# $_[1]: Address
|
||||
# $_[2]: Functionalities of this i2c adapter
|
||||
# Returns: 1 on successful probing, 0 else.
|
||||
# This function is meant to prevent AT24RF08 corruption and write-only
|
||||
# chips locks. This is done by choosing the best probing method depending
|
||||
# on the address range.
|
||||
sub i2c_probe
|
||||
sub i2c_probe($$$)
|
||||
{
|
||||
my ($file, $addr) = @_;
|
||||
my ($file, $addr, $funcs) = @_;
|
||||
my $data = [];
|
||||
if (($addr >= 0x50 && $addr <= 0x5F)
|
||||
|| ($addr >= 0x30 && $addr <= 0x37)) {
|
||||
@@ -2547,8 +2566,10 @@ sub i2c_probe
|
||||
# this, because they ack on write only, but this is probably better since
|
||||
# some EEPROMs write-protect themselves permanently on almost any write to
|
||||
# their page protection address.
|
||||
return 0 unless ($funcs & I2C_FUNC_SMBUS_READ_BYTE);
|
||||
return i2c_smbus_access($file, SMBUS_READ, 0, SMBUS_BYTE, $data);
|
||||
} else {
|
||||
return 0 unless ($funcs & I2C_FUNC_SMBUS_QUICK);
|
||||
return i2c_smbus_access($file, SMBUS_WRITE, 0, SMBUS_QUICK, $data);
|
||||
}
|
||||
}
|
||||
@@ -2799,7 +2820,7 @@ sub add_isa_to_chips_detected
|
||||
sub scan_adapter
|
||||
{
|
||||
my ($adapter_nr, $adapter_name, $adapter_driver, $not_to_scan) = @_;
|
||||
my ($chip, $addr, $conf,@chips,$new_hash,$other_addr);
|
||||
my ($funcs, $chip, $addr, $conf, @chips, $new_hash, $other_addr);
|
||||
|
||||
# As we modify it, we need a copy
|
||||
my @not_to_scan = @$not_to_scan;
|
||||
@@ -2808,6 +2829,21 @@ sub scan_adapter
|
||||
(print "Can't open $dev_i2c$adapter_nr\n"), return;
|
||||
binmode FILE;
|
||||
|
||||
# Can we probe this adapter?
|
||||
$funcs = i2c_get_funcs(\*FILE);
|
||||
if ($funcs < 0) {
|
||||
print "Adapter failed to provide its functionalities, skipping.\n";
|
||||
return;
|
||||
}
|
||||
if (!($funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) {
|
||||
print "Adapter cannot be probed, skipping.\n";
|
||||
return;
|
||||
}
|
||||
if (~$funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE)) {
|
||||
print "Adapter doesn't support all probing functions.\n",
|
||||
"Some addresses won't be probed.\n";
|
||||
}
|
||||
|
||||
# Now scan each address in turn
|
||||
foreach $addr (0x03..0x77) {
|
||||
# As the not_to_scan list is sorted, we can check it fast
|
||||
@@ -2855,7 +2891,7 @@ sub scan_adapter
|
||||
next;
|
||||
}
|
||||
|
||||
next unless i2c_probe(\*FILE, $addr);
|
||||
next unless i2c_probe(\*FILE, $addr, $funcs);
|
||||
printf "Client found at address 0x%02x\n",$addr;
|
||||
|
||||
foreach $chip (@chip_ids) {
|
||||
|
Reference in New Issue
Block a user