root/lm-sensors/trunk/prog/detect/sensors-detect @ 524

Revision 524, 58.4 KB (checked in by mds, 14 years ago)

(mds) Corrected W83782D detection (added ISA).

Corrected W83783S detection (removed ISA).
Added W83627HF detection (chip ID = 0x20).

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#!/usr/bin/perl
2
3#
4#    sensors-detect - Detect PCI bus and chips
5#    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
6#
7#    This program is free software; you can redistribute it and/or modify
8#    it under the terms of the GNU General Public License as published by
9#    the Free Software Foundation; either version 2 of the License, or
10#    (at your option) any later version.
11#
12#    This program is distributed in the hope that it will be useful,
13#    but WITHOUT ANY WARRANTY; without even the implied warranty of
14#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15#    GNU General Public License for more details.
16#
17#    You should have received a copy of the GNU General Public License
18#    along with this program; if not, write to the Free Software
19#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20#
21
22# TODO: Better handling of chips with several addresses
23
24# A Perl wizard really ought to look upon this; the PCI and I2C stuff should
25# each be put in a separate file, using modules and packages. That is beyond
26# me.
27
28require 5.004;
29
30use strict;
31
32#########################
33# CONSTANT DECLARATIONS #
34#########################
35
36use vars qw(@pci_adapters @chip_ids @undetectable_adapters);
37
38@undetectable_adapters = ( "bit-lp", "bit-velle" );
39
40# This is the list of SMBus or I2C adapters we recognize by their PCI
41# signature. This is an easy and fast way to determine which SMBus or I2C
42# adapters should be present.
43# Each entry must have a vindid (Vendor ID), devid (Device ID), func (PCI
44# Function) and procid (string as appears in /proc/pci; see linux/driver/pci,
45# either pci.c or oldproc.c). If no driver is written yet, omit the
46# driver (Driver Name) field. The match (Match Description) field should
47# contain a function which returns zero if its two parameter matches
48# the text as it would appear in /proc/bus/i2c.
49@pci_adapters = ( 
50     { 
51       vendid => 0x8086,
52       devid  => 0x7113,
53       func => 3,
54       procid => "Intel 82371AB PIIX4 ACPI",
55       driver => "i2c-piix4",
56       match => sub { $_[0] =~ /^SMBus PIIX4 adapter at [0-9,a-f]{4}/ },
57     } , 
58     { 
59       vendid => 0x1106,
60       devid  => 0x3040,
61       func => 3,
62       procid => "VIA Technologies VT 82C586B Apollo ACPI",
63       driver => "i2c-via",
64       match => sub { $_[0] =~ /^VIA i2c/ },
65     } ,
66     { 
67       vendid => 0x1106,
68       devid  => 0x3050,
69       func => 3,
70       procid => "VIA Technologies VT 82C596 Apollo ACPI",
71       driver => "i2c-viapro",
72       match => sub { $_[0] =~ /^SMBus vt82c596 adapter at [0-9,a-f]{4}/ },
73     } ,
74     { 
75       vendid => 0x1106,
76       devid  => 0x3057,
77       func => 4,
78       procid => "VIA Technologies VT 82C686 Apollo ACPI",
79       driver => "i2c-viapro",
80       match => sub { $_[0] =~ /^SMBus vt82c596 adapter at [0-9,a-f]{4}/ },
81     } ,
82     {
83       vendid => 0x1039,
84       devid  => 0x0008,
85       func => 0,
86       procid => "Silicon Integrated Systems 85C503",
87       match => sub { 0 },
88     } ,
89     {
90       vendid => 0x10b9,
91       devid => 0x7101,
92       funcid => 0,
93       procid => "Acer Labs M7101",
94       driver => "i2c-ali15x3",
95       match => sub { $_[0] =~ /^SMBus ALI15X3 adapter at [0-9,a-f]{4}/ },
96     },
97     { 
98       vendid => 0x106b,
99       devid  => 0x000e,
100       func => 0,
101       procid => "Apple Computer Inc. Hydra Mac I/O",
102       driver => "i2c-hydra",
103       match => sub { $_[0] =~ /^Hydra i2c/ },
104     },
105);
106
107use subs qw(lm78_detect lm78_isa_detect lm78_alias_detect lm75_detect
108            lm80_detect w83781d_detect w83781d_alias_detect
109            w83781d_isa_detect gl518sm_detect gl520sm_detect adm9240_detect
110            adm1021_detect sis5595_isa_detect eeprom_detect ltc1710_detect);
111
112# This is a list of all recognized chips.
113# Each entry must have the following fields:
114#  name: The full chip name
115#  driver (optional): The driver name (without .o extension). Omit if none is
116#      written yet.
117#  i2c_addrs (optional): For I2C chips, the range of valid I2C addresses to
118#      probe.
119#  i2c_driver_addrs (optional): For I2C chips, the range of valid I2C
120#      addresses probed by the kernel driver. Strictly optional.
121#  i2c_detect (optional): For I2C chips, the function to call to detect
122#      this chip. The function should take two parameters: an open file
123#      descriptor to access the bus, and the I2C address to probe.
124#  isa_addrs (optional): For ISA chips, the range of valid port addresses to
125#      probe.
126#  isa_driver_addrs (optional): For ISA chips, the range of valid ISA
127#      addresses probed by the kernel driver. Strictly optional.
128#  isa_detect (optional): For ISA chips, the function to call to detect
129#      this chip. The function should take one parameter: the ISA address
130#      to probe.
131#  alias_detect (optional): For chips which can be both on the ISA and the
132#      I2C bus, a function which detectes whether two entries are the same.
133#      The function should take three parameters: The ISA address, the
134#      I2C bus number, and the I2C address.
135@chip_ids = (
136     {
137       name => "National Semiconductors LM78",
138       driver => "lm78",
139       i2c_addrs => [0x00..0x7f], 
140       i2c_driver_addrs => [0x20..0x2f], 
141       i2c_detect => sub { lm78_detect 0, @_},
142       isa_addrs => [0x290],
143       isa_detect => sub { lm78_isa_detect 0, @_ },
144       alias_detect => sub { lm78_alias_detect 0, @_ },
145     } ,
146     {
147       name => "National Semiconductors LM78-J",
148       driver => "lm78",
149       i2c_addrs => [0x00..0x7f],
150       i2c_driver_addrs => [0x20..0x2f], 
151       i2c_detect => sub { lm78_detect 1, @_ },
152       isa_addrs => [0x290],
153       isa_detect => sub { lm78_isa_detect 1, @_ },
154       alias_detect => sub { lm78_alias_detect 1, @_ },
155     } ,
156     {
157       name => "National Semiconductors LM79",
158       driver => "lm78",
159       i2c_addrs => [0x00..0x7f],
160       i2c_driver_addrs => [0x20..0x2f], 
161       i2c_detect => sub { lm78_detect 2, @_ },
162       isa_addrs => [0x290],
163       isa_detect => sub { lm78_isa_detect 2, @_ },
164       alias_detect => sub { lm78_alias_detect 2, @_ },
165     } ,
166     {
167       name => "National Semiconductors LM75",
168       driver => "lm75",
169       i2c_addrs => [0x48..0x4f],
170       i2c_detect => sub { lm75_detect @_},
171     } ,
172     {
173       name => "National Semiconductors LM80",
174       driver => "lm80",
175       i2c_addrs => [0x28..0x2f],
176       i2c_detect => sub { lm80_detect @_} ,
177     },
178     {
179       name => "Winbond W83781D",
180       driver => "w83781d",
181       i2c_addrs => [0x00..0x7f], 
182       i2c_detect => sub { w83781d_detect 0, @_},
183       i2c_driver_addrs => [0x20..0x2f], 
184       isa_addrs => [0x290],
185       isa_detect => sub { w83781d_isa_detect 0, @_ },
186       alias_detect => sub { w83781d_alias_detect 0, @_ },
187     } ,
188     {
189       name => "Winbond W83782D",
190       driver => "w83781d",
191       i2c_addrs => [0x00..0x7f], 
192       i2c_driver_addrs => [0x20..0x2f], 
193       i2c_detect => sub { w83781d_detect 1, @_},
194       isa_addrs => [0x290],
195       isa_detect => sub { w83781d_isa_detect 1, @_ },
196       alias_detect => sub { w83781d_alias_detect 1, @_ },
197     } ,
198     {
199       name => "Winbond W83783S",
200       driver => "w83781d",
201       i2c_addrs => [0x00..0x7f], 
202       i2c_driver_addrs => [0x20..0x2f], 
203       i2c_detect => sub { w83781d_detect 2, @_},
204     } ,
205     {
206       name => "Winbond W83627HF",
207       driver => "w83781d",
208       i2c_addrs => [0x00..0x7f], 
209       i2c_driver_addrs => [0x20..0x2f], 
210       i2c_detect => sub { w83781d_detect 3, @_},
211       isa_addrs => [0x290],
212       isa_detect => sub { w83781d_isa_detect 3, @_ },
213       alias_detect => sub { w83781d_alias_detect 3, @_ },
214     } ,
215     {
216       name => "Genesys Logic GL518SM Revision 0x00",
217       driver => "gl518sm",
218       i2c_addrs => [0x2c, 0x2d],
219       i2c_detect => sub { gl518sm_detect 0, @_} ,
220     },
221     {
222       name => "Genesys Logic GL518SM Revision 0x80",
223       driver => "gl518sm",
224       i2c_addrs => [0x2c, 0x2d],
225       i2c_detect => sub { gl518sm_detect 1, @_} ,
226     },
227     {
228       name => "Genesys Logic GL520SM",
229       driver => "gl520sm",
230       i2c_addrs => [0x2c, 0x2d],
231       i2c_detect => sub { gl520sm_detect @_} ,
232     },
233     {
234       name => "Analog Devices ADM9240",
235       driver => "adm9240",
236       i2c_addrs => [0x2c..0x2f],
237       i2c_detect => sub { adm9240_detect 0, @_ }
238     },
239     {
240       name => "Dallas Semiconductor DS1780",
241       driver => "adm9240",
242       i2c_addrs => [0x2c..0x2f],
243       i2c_detect => sub { adm9240_detect 1, @_ }
244     },
245     {
246       name => "Analog Devices ADM1021",
247       driver => "adm1021",
248       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
249       i2c_detect => sub { adm1021_detect 0, @_ },
250     },
251     {
252       name => "Maxim MAX1617",
253       driver => "adm1021",
254       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
255       i2c_detect => sub { adm1021_detect 1, @_ },
256     },
257     {
258       name => "Maxim MAX1617A",
259       driver => "adm1021",
260       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
261       i2c_detect => sub { adm1021_detect 2, @_ },
262     },
263     {
264       name => "Silicon Integrated Systems SIS5595",
265       driver => "sis5595",
266       isa_addrs => [ 0 ],
267       isa_detect => sub { sis5595_isa_detect @_ },
268     },
269     {
270       name => "Serial EEPROM (PC-100 DIMM)",
271       driver => "eeprom",
272       i2c_addrs => [0x50..0x57],
273       i2c_detect => sub { eeprom_detect @_ },
274     },
275     {
276       name => "LTC1710",
277       driver => "ltc1710",
278       i2c_addrs => [0x58..0x5a],
279       i2c_detect => sub { ltc1710_detect @_ },
280     },
281);
282
283
284#######################
285# AUXILIARY FUNCTIONS #
286#######################
287
288sub swap_bytes
289{
290  return (($_[0] & 0xff00) >> 8) + (($_[0] & 0x00ff) << 8)
291}
292
293# $_[0] is the sought value
294# @_[1..] is the list to seek in
295# Returns: 0 on failure, 1 if found.
296sub contains
297{
298  my $sought = shift;
299  foreach (@_) {
300    return 1 if $sought eq $_;
301  }
302  return 0;
303}
304
305sub parse_not_to_scan
306{
307  my ($min,$max,$to_parse) = @_;
308  my @ranges = split /\s*,\s*/, $to_parse;
309  my @res = ();
310  my $range;
311  foreach $range (@ranges) {
312    my ($start,$end) = split /\s*-s*/, $range;
313    $start = oct $start if $start =~ /^0/;
314    if (defined $end) {
315      $end = oct $end if $end =~ /^0/;
316      $start = $min if $start < $min;
317      $end = $max if $end > $max;
318      push @res, ($start+0..$end+0);
319    } else {
320      push @res, $start+0 if $start >= $min and $start <= $max;
321    }
322  }
323  return sort { $a <=> $b } @res;
324}
325
326# @_[0]: Reference to list 1
327# @_[1]: Reference to list 2
328# Result: 0 if they have no elements in common, 1 if they have
329# Elements must be numeric.
330sub any_list_match
331{
332  my ($list1,$list2) = @_;
333  my ($el1,$el2);
334  foreach $el1 (@$list1) {
335    foreach $el2 (@$list2) {
336      return 1 if $el1 == $el2;
337    }
338  }
339  return 0;
340}
341
342###################
343# I/O port access #
344###################
345
346sub initialize_ioports
347{
348  sysopen IOPORTS, "/dev/port", 2;
349}
350
351# $_[0]: port to read
352# Returns: -1 on failure, read value on success.
353sub inb
354{
355  my ($res,$nrchars);
356  sysseek IOPORTS, $_[0], 0 or return -1;
357  $nrchars = sysread IOPORTS, $res, 1;
358  return -1 if not defined $nrchars or $nrchars != 1;
359  $res = unpack "C",$res ;
360  return $res;
361}
362
363# $_[0]: port to write
364# $_[1]: value to write
365# Returns: -1 on failure, 0 on success.
366sub outb
367{
368  my $towrite = pack "C", $_[1];
369  sysseek IOPORTS, $_[0], 0 or return -1;
370  my $nrchars = syswrite IOPORTS, $towrite, 1;
371  return -1 if not defined $nrchars or $nrchars != 1;
372  return 0;
373}
374
375# $_[0]: Address register
376# $_[1]: Data register
377# $_[2]: Register to read
378# Returns: read value
379sub isa_read_byte
380{
381  outb $_[0],$_[2];
382  return inb $_[1];
383}
384
385# $_[0]: Address register
386# $_[1]: Data register
387# $_[2]: Register to write
388# $_[3}: Value to write
389# Returns: nothing
390sub isa_write_byte
391{
392  outb $_[0],$_[2];
393  outb $_[1],$_[3];
394}
395
396###########
397# MODULES #
398###########
399
400use vars qw(@modules_list);
401
402sub initialize_modules_list
403{
404  open INPUTFILE, "/proc/modules" or die "Can't access /proc/modules!";
405  while (<INPUTFILE>) {
406    push @modules_list, /^(\S*)/ ;
407  }
408  close INPUTFILE;
409}
410
411##############
412# PCI ACCESS #
413##############
414
415use vars qw(@pci_list);
416
417# This function returns a list of hashes. Each hash has some PCI information
418# (more than we will ever need, probably). The most important
419# fields are 'bus', 'slot', 'func' (they uniquely identify a PCI device in
420# a computer) and 'vendid','devid' (they uniquely identify a type of device).
421# /proc/bus/pci/devices is only available on late 2.1 and 2.2 kernels.
422sub read_proc_dev_pci
423{
424  my ($dfn,$vend,@pci_list);
425  open INPUTFILE, "/proc/bus/pci/devices" or return;
426  while (<INPUTFILE>) {
427    my $record = {};
428    ($dfn,$vend,$record->{irq},$record->{base_addr0},$record->{base_addr1},
429          $record->{base_addr2},$record->{base_addr3},$record->{base_addr4},
430          $record->{base_addr5},$record->{rom_base_addr}) = 
431          map { oct "0x$_" } split;
432    $record->{bus} = $dfn >> 8;
433    $record->{slot} = ($dfn & 0xf8) >> 3;
434    $record->{func} = $dfn & 0x07;
435    $record->{vendid} = $vend >> 16;
436    $record->{devid} = $vend & 0xffff;
437  push @pci_list,$record;
438  }
439  close INPUTFILE or return;
440  return @pci_list;
441}
442
443# This function returns a list of hashes. Each hash has some PCI
444# information. The important fields here are 'bus', 'slot', 'func' (they
445# uniquely identify a PCI device in a computer) and 'desc' (a functional
446# description of the PCI device). If this is an 'unknown device', the
447# vendid and devid fields are set instead.
448sub read_proc_pci
449{
450  my @pci_list;
451  open INPUTFILE, "/proc/pci" or return;
452  while (<INPUTFILE>) {
453    my $record = {};
454    if (($record->{bus},$record->{slot},$record->{func}) = 
455        /^\s*Bus\s*(\S)+\s*,\s*device\s*(\S+)\s*,\s*function\s*(\S+)\s*:\s*$/) {
456      my $desc = <INPUTFILE>;
457      unless (($desc =~ /Unknown device/) and
458              (($record->{vendid},$record->{devid}) = 
459                         /^\s*Vendor id=(\S+)\.\s*Device id=(\S+)\.$/)) {
460        $record->{desc} = $desc;
461      }
462      push @pci_list,$record;
463    }
464  }
465  close INPUTFILE or return;
466  return @pci_list;
467}
468
469sub initialize_proc_pci
470{
471  @pci_list = read_proc_dev_pci;
472  @pci_list = read_proc_pci     if not defined @pci_list;
473  die "Can't access either /proc/bus/pci/ or /proc/pci!" 
474                                    if not defined @pci_list;
475}
476
477#####################
478# ADAPTER DETECTION #
479#####################
480
481sub all_available_adapters
482{
483  my @res = ();
484  my ($module,$adapter);
485  MODULES:
486  foreach $module (@modules_list) {
487    foreach $adapter (@pci_adapters) {
488      if (exists $adapter->{driver} and $module eq $adapter->{driver}) {
489        push @res, $module;
490        next MODULES;
491      }
492    }
493  }
494  return @res;
495}
496
497sub adapter_pci_detection
498{
499  my ($device,$try,@res);
500  print "Probing for PCI bus adapters...\n";
501
502  foreach $device (@pci_list) {
503    foreach $try (@pci_adapters) {
504      if ((defined($device->{vendid}) and 
505           $try->{vendid} == $device->{vendid} and
506           $try->{devid} == $device->{devid} and
507           $try->{func} == $device->{func}) or
508          (! defined($device->{vendid}) and
509           $device->{desc} =~ /$try->{procid}/ and
510           $try->{func} == $device->{func})) {
511        printf "Use driver `%s' for device %02x:%02x.%x: %s\n",
512               $try->{driver}?$try->{driver}:"<To Be Written>",
513               $device->{bus},$device->{slot},$device->{func},$try->{procid};
514        push @res,$try->{driver};
515      }
516    }
517  }
518  if (! defined @res) {
519    print ("Sorry, no PCI bus adapters found.\n");
520  } else {
521    printf ("Probe succesfully concluded.\n");
522  }
523  return @res;
524}
525
526# $_[0]: Adapter description as found in /proc/bus/i2c
527# $_[1]: Algorithm description as found in /proc/bus/i2c
528sub find_adapter_driver
529{
530  my $adapter;
531  for $adapter (@pci_adapters) {
532    return $adapter->{driver} if &{$adapter->{match}} ($_[0],$_[1]);
533  }
534  return "?????";
535}
536
537#############################
538# I2C AND SMBUS /DEV ACCESS #
539#############################
540
541# This should really go into a separate module/package.
542
543# To do: support i2c-level access (through sysread/syswrite, probably).
544# I can't test this at all (PIIX4 does not support this), so I have not
545# included it.
546
547use vars qw($IOCTL_I2C_RETRIES $IOCTL_I2C_TIMEOUT $IOCTL_I2C_UDELAY
548            $IOCTL_I2C_MDELAY $IOCTL_I2C_SLAVE $IOCTL_I2C_TENBIT
549            $IOCTL_I2C_SMBUS);
550
551# These are copied from <linux/i2c.h> and <linux/smbus.h>
552
553# For bit-adapters:
554$IOCTL_I2C_RETRIES = 0x0701;
555$IOCTL_I2C_TIMEOUT = 0x0702;
556$IOCTL_I2C_UDELAY = 0x0705;
557$IOCTL_I2C_MDELAY = 0x0706;
558
559# General ones:
560$IOCTL_I2C_SLAVE = 0x0703;
561$IOCTL_I2C_TENBIT = 0x0704;
562$IOCTL_I2C_SMBUS = 0x0720;
563
564
565use vars qw($SMBUS_READ $SMBUS_WRITE $SMBUS_QUICK $SMBUS_BYTE $SMBUS_BYTE_DATA
566            $SMBUS_WORD_DATA $SMBUS_PROC_CALL $SMBUS_BLOCK_DATA);
567
568# These are copied from <linux/smbus.h>
569
570$SMBUS_READ = 1;
571$SMBUS_WRITE = 0;
572$SMBUS_QUICK = 0;
573$SMBUS_BYTE = 1;
574$SMBUS_BYTE_DATA  = 2;
575$SMBUS_WORD_DATA  = 3;
576$SMBUS_PROC_CALL = 4;
577$SMBUS_BLOCK_DATA = 5;
578
579# Select the device to communicate with through its address.
580# $_[0]: Reference to an opened filehandle
581# $_[1]: Address to select
582# Returns: 0 on failure, 1 on success.
583sub i2c_set_slave_addr
584{
585  my ($file,$addr) = @_;
586  ioctl $file, $IOCTL_I2C_SLAVE, $addr or return 0;
587  return 1;
588}
589
590# i2c_smbus_access is based upon the corresponding C function (see
591# <linux/i2c-dev.h>). You should not need to call this directly.
592# Exact calling conventions are intricate; read i2c-dev.c if you really need
593# to know.
594# $_[0]: Reference to an opened filehandle
595# $_[1]: $SMBUS_READ for reading, $SMBUS_WRITE for writing
596# $_[2]: Command (usually register number)
597# $_[3]: Transaction kind ($SMBUS_BYTE, $SMBUS_BYTE_DATA, etc.)
598# $_[4]: Reference to an array used for input/output of data
599# Returns: 0 on failure, 1 on success.
600# Note that we need to get back to Integer boundaries through the 'x2'
601# in the pack. This is very compiler-dependent; I wish there was some other
602# way to do this.
603sub i2c_smbus_access
604{
605  my ($file,$read_write,$command,$size,$data) = @_;
606  my $data_array = pack "C32", @$data;
607  my $ioctl_data = pack "C2x2Ip", ($read_write,$command,$size,$data_array);
608  ioctl $file, $IOCTL_I2C_SMBUS, $ioctl_data or return 0;
609  $_[4] = [ unpack "C32",$data_array ];
610  return 1;
611}
612
613# $_[0]: Reference to an opened filehandle
614# $_[1]: Either 0 or 1
615# Returns: -1 on failure, the 0 on success.
616sub i2c_smbus_write_quick
617{
618  my ($file,$value) = @_;
619  my $data = [];
620  i2c_smbus_access $file, $value, 0, $SMBUS_QUICK, $data 
621         or return -1;
622  return 0;
623}
624
625# $_[0]: Reference to an opened filehandle
626# Returns: -1 on failure, the read byte on success.
627sub i2c_smbus_read_byte
628{
629  my ($file) = @_;
630  my $data = [];
631  i2c_smbus_access $file, $SMBUS_READ, 0, $SMBUS_BYTE, $data 
632         or return -1;
633  return $$data[0];
634}
635
636# $_[0]: Reference to an opened filehandle
637# $_[1]: Byte to write
638# Returns: -1 on failure, 0 on success.
639sub i2c_smbus_write_byte
640{
641  my ($file,$command) = @_;
642  my $data = [$command];
643  i2c_smbus_access $file, $SMBUS_WRITE, 0, $SMBUS_BYTE, $data 
644         or return -1;
645  return 0;
646}
647
648# $_[0]: Reference to an opened filehandle
649# $_[1]: Command byte (usually register number)
650# Returns: -1 on failure, the read byte on success.
651sub i2c_smbus_read_byte_data
652{
653  my ($file,$command) = @_;
654  my $data = [];
655  i2c_smbus_access $file, $SMBUS_READ, $command, $SMBUS_BYTE_DATA, $data 
656         or return -1;
657  return $$data[0];
658}
659 
660# $_[0]: Reference to an opened filehandle
661# $_[1]: Command byte (usually register number)
662# $_[2]: Byte to write
663# Returns: -1 on failure, 0 on success.
664sub i2c_smbus_write_byte_data
665{
666  my ($file,$command,$value) = @_;
667  my $data = [$value];
668  i2c_smbus_access $file, $SMBUS_WRITE, $command, $SMBUS_BYTE_DATA, $data 
669         or return -1;
670  return 0;
671}
672
673# $_[0]: Reference to an opened filehandle
674# $_[1]: Command byte (usually register number)
675# Returns: -1 on failure, the read word on success.
676# Note: some devices use the wrong endiannes; use swap_bytes to correct for
677# this.
678sub i2c_smbus_read_word_data
679{
680  my ($file,$command) = @_;
681  my $data = [];
682  i2c_smbus_access $file, $SMBUS_READ, $command, $SMBUS_WORD_DATA, $data 
683         or return -1;
684  return $$data[0] + 256 * $$data[1];
685}
686
687# $_[0]: Reference to an opened filehandle
688# $_[1]: Command byte (usually register number)
689# $_[2]: Byte to write
690# Returns: -1 on failure, 0 on success.
691# Note: some devices use the wrong endiannes; use swap_bytes to correct for
692# this.
693sub i2c_smbus_write_word_data
694{
695  my ($file,$command,$value) = @_;
696  my $data = [$value & 0xff, $value >> 8];
697  i2c_smbus_access $file, $SMBUS_WRITE, $command, $SMBUS_WORD_DATA, $data 
698         or return -1;
699  return 0;
700}
701
702# $_[0]: Reference to an opened filehandle
703# $_[1]: Command byte (usually register number)
704# $_[2]: Word to write
705# Returns: -1 on failure, read word on success.
706# Note: some devices use the wrong endiannes; use swap_bytes to correct for
707# this.
708sub i2c_smbus_process_call
709{
710  my ($file,$command,$value) = @_;
711  my $data = [$value & 0xff, $value >> 8];
712  i2c_smbus_access $file, $SMBUS_WRITE, $command, $SMBUS_PROC_CALL, $data 
713         or return -1;
714  return $$data[0] + 256 * $$data[1];
715}
716
717# $_[0]: Reference to an opened filehandle
718# $_[1]: Command byte (usually register number)
719# Returns: Undefined on failure, a list of read bytes on success
720# Note: some devices use the wrong endiannes; use swap_bytes to correct for
721# this.
722sub i2c_smbus_read_block_data
723{
724  my ($file,$command) = @_;
725  my $data = [];
726  i2c_smbus_access $file, $SMBUS_READ, $command, $SMBUS_BLOCK_DATA, $data 
727         or return;
728  shift @$data;
729  return @$data;
730}
731
732# $_[0]: Reference to an opened filehandle
733# $_[1]: Command byte (usually register number)
734# @_[2..]: List of values to write
735# Returns: -1 on failure, 0 on success.
736# Note: some devices use the wrong endiannes; use swap_bytes to correct for
737# this.
738sub i2c_smbus_write_block_data
739{
740  my ($file,$command,@data) = @_;
741  i2c_smbus_access $file, $SMBUS_WRITE, $command, $SMBUS_BLOCK_DATA, \@data 
742         or return;
743  return 0;
744}
745
746####################
747# ADAPTER SCANNING #
748####################
749
750use vars qw(@chips_detected);
751
752# We will build a complicated structure @chips_detected here, being:
753# A list of
754#  references to hashes
755#    with field 'driver', being a string with the driver name for this chip;
756#    with field 'detected'
757#      being a reference to a list of
758#        references to hashes of type 'detect_data';
759#    with field 'misdetected'
760#      being a reference to a list of
761#        references to hashes of type 'detect_data'
762
763# Type detect_data:
764# A hash
765#   with field 'i2c_adap' containing an adapter string as appearing
766#        in /proc/bus/i2c (if this is an I2C detection)
767#  with field 'i2c_algo' containing an algorithm string as appearing
768#       in /proc/bus/i2c (if this is an I2C detection)
769#  with field 'i2c_devnr', contianing the /dev/i2c-* number of this
770#       adapter (if this is an I2C detection)
771#  with field 'i2c_driver', containing the driver name for this adapter
772#       (if this is an I2C detection)
773#  with field 'i2c_addr', containing the I2C address of the detection;
774#       (if this is an I2C detection)
775#  with field 'i2c_sub_addrs', containing a reference to a list of
776#       other I2C addresses (if this is an I2C detection)
777#  with field 'i2c_extra' if this is an I2C detection and the address
778#       is not normally probed by the kernel driver
779#  with field 'isa_addr' containing the ISA address this chip is on
780#       (if this is an ISA detection)
781#  with field 'isa_extra' if this is an ISA detection and the address
782#       is not normally probed by the kernel driver
783#  with field 'conf', containing the confidence level of this detection
784#  with field 'chipname', containing the chip name
785
786# This adds a detection to the above structure. We do no alias detection
787# here; so you should do ISA detections *after* all I2C detections.
788# Not all possibilities of i2c_addr and i2c_sub_addrs are exhausted.
789# In all normal cases, it should be all right.
790# $_[0]: chip driver
791# $_[1]: reference to data hash
792# Returns: Nothing
793sub add_i2c_to_chips_detected
794{
795  my ($chipdriver,$datahash) = @_;
796  my ($i,$new_detected_ref,$new_misdetected_ref,$detected_ref,$misdetected_ref,
797      $main_entry,$detected_entry,$put_in_detected,@hash_addrs,@entry_addrs);
798
799  # First determine where the hash has to be added.
800  for ($i = 0; $i < @chips_detected; $i++) {
801    last if ($chips_detected[$i]->{driver} eq $chipdriver);
802  }
803  if ($i == @chips_detected) {
804    push @chips_detected, { driver => $chipdriver,
805                            detected => [],
806                            misdetected => [] };
807  }
808  $new_detected_ref = $chips_detected[$i]->{detected};
809  $new_misdetected_ref = $chips_detected[$i]->{misdetected};
810
811  # Find out whether our new entry should go into the detected or the
812  # misdetected list. We compare all i2c addresses; if at least one matches,
813  # but our conf value is lower, we assume this is a misdetect.
814  @hash_addrs = ($datahash->{i2c_addr});
815  push @hash_addrs, @{$datahash->{i2c_sub_addrs}}
816       if exists $datahash->{i2c_sub_addrs};
817  $put_in_detected = 1;
818  FIND_LOOP:
819  foreach $main_entry (@chips_detected) {
820    foreach $detected_entry (@{$main_entry->{detected}}) {
821      @entry_addrs = ($detected_entry->{i2c_addr});
822      push @entry_addrs, @{$detected_entry->{i2c_sub_addrs}}
823               if exists $detected_entry->{i2c_sub_addrs};
824      if ($detected_entry->{i2c_devnr} == $datahash->{i2c_devnr} and
825          any_list_match \@entry_addrs, \@hash_addrs) {
826        if ($detected_entry->{conf} >= $datahash->{conf}) {
827          $put_in_detected = 0;
828        }
829        last FIND_LOOP;
830      }
831    }
832  }
833
834  if ($put_in_detected) {
835    # Here, we move all entries from detected to misdetected which
836    # match at least in one main or sub address. This may not be the
837    # best idea to do, as it may remove detections without replacing
838    # them with second-best ones. Too bad.
839    @hash_addrs = ($datahash->{i2c_addr});
840    push @hash_addrs, @{$datahash->{i2c_sub_addrs}} 
841         if exists $datahash->{i2c_sub_addrs};
842    foreach $main_entry (@chips_detected) {
843      $detected_ref = $main_entry->{detected};
844      $misdetected_ref = $main_entry->{misdetected};
845      for ($i = @$detected_ref-1; $i >=0; $i--) {
846        @entry_addrs = ($detected_ref->[$i]->{i2c_addr});
847        push @entry_addrs, @{$detected_ref->[$i]->{i2c_sub_addrs}}
848             if exists $detected_ref->[$i]->{i2c_sub_addrs};
849        if (any_list_match \@entry_addrs, \@hash_addrs) {
850          push @$misdetected_ref,$detected_ref->[$i];
851          splice @$detected_ref, $i, 1;
852        }
853      }
854    }
855
856    # Now add the new entry to detected
857    push @$new_detected_ref, $datahash;
858  } else {
859    # No hard work here
860    push @$new_misdetected_ref, $datahash;
861  }
862}
863
864# This adds a detection to the above structure. We also do alias detection
865# here; so you should do ISA detections *after* all I2C detections.
866# $_[0]: alias detection function
867# $_[1]: chip driver
868# $_[2]: reference to data hash
869# Returns: Nothing
870sub add_isa_to_chips_detected
871{
872  my ($alias_detect,$chipdriver,$datahash) = @_;
873  my ($i,$new_detected_ref,$new_misdetected_ref,$detected_ref,$misdetected_ref,
874      $main_entry);
875
876  # First determine where the hash has to be added.
877  for ($i = 0; $i < @chips_detected; $i++) {
878    last if ($chips_detected[$i]->{driver} eq $chipdriver);
879  }
880  if ($i == @chips_detected) {
881    push @chips_detected, { driver => $chipdriver,
882                            detected => [],
883                            misdetected => [] };
884  }
885  $new_detected_ref = $chips_detected[$i]->{detected};
886  $new_misdetected_ref = $chips_detected[$i]->{misdetected};
887
888  # Now, we are looking for aliases. An alias can only be the same chiptype.
889  # If an alias is found in the misdetected list, we add the new information
890  # and terminate this function. If it is found in the detected list, we
891  # still have to check whether another chip has claimed this ISA address.
892  # So we remove the old entry from the detected list and put it in datahash.
893
894  # Misdetected alias detection:
895  for ($i = 0; $i < @$new_misdetected_ref; $i++) {
896    if (exists $new_misdetected_ref->[$i]->{i2c_addr} and
897        not exists $new_misdetected_ref->[$i]->{isa_addr} and
898        defined $alias_detect and
899        $new_misdetected_ref->[$i]->{chipname} eq $datahash->{chipname}) {
900      open FILE,"/dev/i2c-$new_misdetected_ref->[$i]->{i2c_devnr}" or
901           print("Can't open ",
902                 "/dev/i2c-$new_misdetected_ref->[$i]->{i2c_devnr}?!?\n"),
903           next;
904      i2c_set_slave_addr \*FILE,$new_misdetected_ref->[$i]->{i2c_addr} or
905           print("Can't set I2C address for ",
906                 "/dev/i2c-$new_misdetected_ref->[$i]->{i2c_devnr}?!?\n"),
907           next;
908      if (&$alias_detect ($datahash->{isa_addr},\*FILE,
909                          $new_misdetected_ref->[$i]->{i2c_addr})) {
910        $new_misdetected_ref->[$i]->{isa_addr} = $datahash->{isa_addr};
911        $new_misdetected_ref->[$i]->{isa_extra} = $datahash->{isa_extra} 
912               if exists $datahash->{isa_extra};
913        close FILE;
914        return;
915      }
916      close FILE;
917    }
918  }
919
920  # Detected alias detection:
921  for ($i = 0; $i < @$new_detected_ref; $i++) {
922    if (exists $new_detected_ref->[$i]->{i2c_addr} and
923        not exists $new_detected_ref->[$i]->{isa_addr} and
924        defined $alias_detect and
925        $new_detected_ref->[$i]->{chipname} eq $datahash->{chipname}) {
926      open FILE,"/dev/i2c-$new_detected_ref->[$i]->{i2c_devnr}" or
927           print("Can't open ",
928                 "/dev/i2c-$new_detected_ref->[$i]->{i2c_devnr}?!?\n"),
929           next;
930      i2c_set_slave_addr \*FILE,$new_detected_ref->[$i]->{i2c_addr} or
931           print("Can't set I2C address for ",
932                 "/dev/i2c-$new_detected_ref->[$i]->{i2c_devnr}?!?\n"),
933           next;
934      if (&$alias_detect ($datahash->{isa_addr},\*FILE,
935                          $new_detected_ref->[$i]->{i2c_addr})) {
936        $new_detected_ref->[$i]->{isa_addr} = $datahash->{isa_addr};
937        $new_detected_ref->[$i]->{isa_extra} = $datahash->{isa_extra} 
938               if exists $datahash->{isa_extra};
939        ($datahash) = splice (@$new_detected_ref, $i, 1);
940        close FILE;
941        last;
942      }
943      close FILE;
944    }
945  }
946
947
948  # Find out whether our new entry should go into the detected or the
949  # misdetected list. We only compare main isa_addr here, of course.
950  foreach $main_entry (@chips_detected) {
951    $detected_ref = $main_entry->{detected};
952    $misdetected_ref = $main_entry->{misdetected};
953    for ($i = 0; $i < @{$main_entry->{detected}}; $i++) {
954      if (exists $detected_ref->[$i]->{isa_addr} and
955          $detected_ref->[$i]->{isa_addr} == $datahash->{isa_addr}) {
956        if ($detected_ref->[$i]->{conf} >= $datahash->{conf}) {
957          push @$new_misdetected_ref, $datahash;
958        } else {
959          push @$misdetected_ref,$detected_ref->[$i];
960          splice @$detected_ref, $i,1;
961          push @$new_detected_ref, $datahash;
962        }
963        return;
964      }
965    }
966  }
967
968  # Not found? OK, put it in the detected list
969  push @$new_detected_ref, $datahash;
970}
971
972# $_[0]: The number of the adapter to scan
973# $_[1]: The name of the adapter, as appearing in /proc/bus/i2c
974# $_[2]: The name of the algorithm, as appearing in /proc/bus/i2c
975# $_[3]: The driver of the adapter
976# @_[4..]: Addresses not to scan
977sub scan_adapter
978{
979  my ( $adapter_nr,$adapter_name,$algorithm_name,$adapter_driver, 
980       $not_to_scan) = @_;
981  my ($chip, $addr, $conf,@chips,$new_hash,$other_addr);
982
983  # As we modify it, we need a copy
984  my @not_to_scan = @$not_to_scan;
985
986  open FILE,"/dev/i2c-$adapter_nr" or 
987       (print "Can't open /dev/i2c-$adapter_nr ($!)\n"), return;
988
989  # Now scan each address in turn
990  foreach $addr (0..0x7f) {
991    # As the not_to_scan list is sorted, we can check it fast
992    if (@not_to_scan and $not_to_scan[0] == $addr) {
993      shift @not_to_scan;
994      next;
995    }
996
997    i2c_set_slave_addr(\*FILE,$addr) or print("Can't set address to $_?!?\n"), 
998                                     next;
999
1000    next unless i2c_smbus_write_quick(\*FILE,$SMBUS_WRITE) >= 0;
1001    printf "Client found at address 0x%02x\n",$addr;
1002
1003    foreach $chip (@chip_ids) {
1004      if (exists $$chip{i2c_addrs} and contains $addr, @{$$chip{i2c_addrs}}) {
1005        print "Probing for `$$chip{name}'... ";
1006        if (($conf,@chips) = &{$$chip{i2c_detect}} (\*FILE ,$addr)) {
1007          print "Success!\n",
1008                "    (confidence $conf, driver `$$chip{driver}'";
1009          if (@chips) {
1010            print ", other addresses:";
1011            @chips = sort @chips;
1012            foreach $other_addr (sort @chips) {
1013              printf(" 0x%02x",$other_addr);
1014            }
1015          }
1016          printf "\n";
1017          $new_hash = { conf => $conf,
1018                        i2c_addr => $addr,
1019                        chipname =>  $$chip{name},
1020                        i2c_adap => $adapter_name,
1021                        i2c_algo => $algorithm_name,
1022                        i2c_driver => $adapter_driver,
1023                        i2c_devnr => $adapter_nr,
1024                      };
1025          if (@chips) {
1026            my @chips_copy = @chips;
1027            $new_hash->{i2c_sub_addrs} = \@chips_copy;
1028          }
1029          $new_hash->{i2c_extra} = 0 
1030                 if exists $chip->{i2c_driver_addrs} and
1031                    not contains( $addr , @{$chip->{i2c_driver_addrs}});
1032          add_i2c_to_chips_detected $$chip{driver}, $new_hash;
1033        } else {
1034          print "Failed!\n";
1035        }
1036      }
1037    }
1038  }
1039}
1040
1041sub scan_isa_bus
1042{
1043  my ($chip,$addr,$conf);
1044  foreach $chip (@chip_ids) {
1045    next if not exists $$chip{isa_addrs} or not exists $$chip{isa_detect};
1046    print "Probing for `$$chip{name}'\n";
1047    foreach $addr (@{$$chip{isa_addrs}}) {
1048      if ($addr) {
1049        printf "  Trying address 0x%04x... ", $addr;
1050      } else {
1051        print "  Trying general detect... ";
1052      }
1053      $conf = &{$$chip{isa_detect}} ($addr);
1054      print("Failed!\n"), next if not defined $conf;
1055      print "Success!\n";
1056      printf "    (confidence %d, driver `%s')\n", $conf, $$chip{driver};
1057      my $new_hash = { conf => $conf,
1058                       isa_addr => $addr,
1059                       chipname =>  $$chip{name}
1060                     };
1061      $new_hash->{isa_extra} = 0 
1062             if exists $chip->{isa_driver_addrs} and
1063                not contains ($addr, @{$chip->{isa_driver_addrs}});
1064      add_isa_to_chips_detected $$chip{alias_detect},$$chip{driver},$new_hash;
1065    }
1066  }
1067}
1068
1069
1070##################
1071# CHIP DETECTION #
1072##################
1073
1074# Each function returns a confidence value. The higher this value, the more
1075# sure we are about this chip. A Winbond W83781D, for example, will be
1076# detected as a LM78 too; but as the Winbond detection has a higher confidence
1077# factor, you should identify it as a Winbond.
1078
1079# Each function returns a list. The first element is the confidence value;
1080# Each element after it is an SMBus address. In this way, we can detect
1081# chips with several SMBus addresses. The SMBus address for which the
1082# function was called is never returned.
1083
1084# If there are devices which get confused if they are only read from, then
1085# this program will surely confuse them. But we guarantee never to write to
1086# any of these devices.
1087
1088
1089# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
1090# $_[1]: A reference to the file descriptor to access this chip.
1091#        We may assume an i2c_set_slave_addr was already done.
1092# $_[2]: Address
1093# Returns: undef if not detected, (7) if detected.
1094# Registers used:
1095#   0x40: Configuration
1096#   0x48: Full I2C Address
1097#   0x49: Device ID
1098# Note that this function is always called through a closure, so the
1099# arguments are shifted by one place.
1100sub lm78_detect
1101{
1102  my $reg;
1103  my ($chip,$file,$addr) = @_;
1104  return unless i2c_smbus_read_byte_data($file,0x48) == $addr;
1105  return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
1106  $reg = i2c_smbus_read_byte_data($file,0x49);
1107  return unless ($chip == 0 and $reg == 0x00) or
1108                    ($chip == 1 and $reg == 0x40) or
1109                    ($chip == 2 and ($reg & 0xfe) == 0xc0);
1110  return (7);
1111}
1112
1113# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
1114# $_[1]: Address
1115# Returns: undef if not detected, 7 if detected.
1116# Note: Only address 0x290 is scanned at this moment.
1117sub lm78_isa_detect
1118{
1119  my ($chip,$addr) = @_ ;
1120  my $val = inb ($addr + 1);
1121  return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or 
1122            inb ($addr + 7) != $val;
1123
1124  $val = inb($addr + 5) & 0x7f;
1125  outb($addr+5,~ $val);
1126  if ((inb ($addr+5) & 0x7f) != (~ $val & 0x7f)) {
1127    outb($addr+5,$val);
1128    return;
1129  }
1130  my $readproc = sub { isa_read_byte $addr + 5, $addr + 6, @_ };
1131  return unless (&$readproc(0x40) & 0x80) == 0x00;
1132  my $reg = &$readproc(0x49);
1133  return unless ($chip == 0 and $reg == 0x00) or
1134                ($chip == 1 and $reg == 0x40) or
1135                ($chip == 2 and ($reg & 0xfe) == 0xc0);
1136  return 7;
1137}
1138
1139
1140# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
1141# $_[1]: ISA address
1142# $_[2]: I2C file handle
1143# $_[3]: I2C address
1144sub lm78_alias_detect
1145{
1146  my ($chip,$isa_addr,$file,$i2c_addr) = @_;
1147  my $i;
1148  my $readproc = sub { isa_read_byte $isa_addr + 5, $isa_addr + 6, @_ };
1149  return 0 unless &$readproc(0x48) == $i2c_addr;
1150  for ($i = 0x2b; $i <= 0x3d; $i ++) {
1151    return 0 unless &$readproc($i) == i2c_smbus_read_byte_data($file,$i);
1152  }
1153  return 1;
1154}
1155
1156# $_[0]: A reference to the file descriptor to access this chip.
1157#        We may assume an i2c_set_slave_addr was already done.
1158# $_[1]: Address
1159# Returns: undef if not detected, (3) if detected.
1160# Registers used:
1161#   0x01: Configuration
1162#   0x02: Hysteris
1163#   0x03: Overtemperature Shutdown
1164# Detection really sucks! It is only based on the fact that the LM75 has only
1165# four registers. Any other chip in the valid address range with only four
1166# registers will be detected too.
1167# Note that register $00 may change, so we can't use the modulo trick on it.
1168sub lm75_detect
1169{
1170  my $i;
1171  my ($file,$addr) = @_;
1172  my $cur = i2c_smbus_read_word_data($file,0x00);
1173  my $conf = i2c_smbus_read_byte_data($file,0x01);
1174  my $hyst = i2c_smbus_read_word_data($file,0x02);
1175  my $os = i2c_smbus_read_word_data($file,0x03);
1176  for ($i = 0x00; $i <= 0x1f; $i += 1) {
1177    return if i2c_smbus_read_byte_data($file,($i * 0x08) + 0x01) != $conf;
1178    return if i2c_smbus_read_word_data($file,($i * 0x08) + 0x02) != $hyst;
1179    return if i2c_smbus_read_word_data($file,($i * 0x08) + 0x03) != $os;
1180  }
1181  return (3);
1182}
1183 
1184
1185# $_[0]: A reference to the file descriptor to access this chip.
1186#        We may assume an i2c_set_slave_addr was already done.
1187# $_[1]: Address
1188# Returns: undef if not detected, (3) if detected.
1189# Registers used:
1190# Registers used:
1191#   0x02: Interrupt state register
1192# How to detect this beast?
1193sub lm80_detect
1194{
1195  my $i;
1196  my ($file,$addr) = @_;
1197  return if (i2c_smbus_read_byte_data($file,$0x02) & 0xc0) != 0;
1198  for ($i = 0x2a; $i <= 0x3d; $i++) {
1199    my $reg = i2c_smbus_read_byte_data($file,$i);
1200    return if i2c_smbus_read_byte_data($file,$i+0x40) != $reg;
1201    return if i2c_smbus_read_byte_data($file,$i+0x80) != $reg;
1202    return if i2c_smbus_read_byte_data($file,$i+0xc0) != $reg;
1203  }
1204  return (3);
1205}
1206 
1207# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 2 = W83783S, 3 = W83627HF)
1208# $_[1]: A reference to the file descriptor to access this chip.
1209#        We may assume an i2c_set_slave_addr was already done.
1210# $_[2]: Address
1211# Returns: undef if not detected, (8,addr1,addr2) if detected, but only
1212#          if the LM75 chip emulation is enabled.
1213# Registers used:
1214#   0x48: Full I2C Address
1215#   0x4a: I2C addresses of emulated LM75 chips
1216#   0x4e: Vendor ID byte selection, and bank selection
1217#   0x4f: Vendor ID
1218#   0x58: Device ID (only when in bank 0); both 0x10 and 0x11 is seen for
1219#         W83781D though Winbond documents 0x10 only.
1220# Note: Fails if the W8378xD is not in bank 0!
1221# Note: Detection overrules a previous LM78 detection
1222sub w83781d_detect
1223{
1224  my ($reg1,$reg2,@res);
1225  my ($chip,$file,$addr) = @_;
1226  return unless i2c_smbus_read_byte_data($file,0x48) == $addr;
1227  $reg1 = i2c_smbus_read_byte_data($file,0x4e);
1228  $reg2 = i2c_smbus_read_byte_data($file,0x4f);
1229  return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or 
1230                (($reg1 & 0x80) == 0x80 and $reg2 == 0x5c);
1231  return unless ($reg1 & 0x07) == 0x00;
1232  $reg1 = i2c_smbus_read_byte_data($file,0x58) & 0xfe;
1233  return if $chip == 0 and  $reg1 != 0x10;
1234  return if $chip == 1 and  $reg1 != 0x30;
1235  return if $chip == 2 and  $reg1 != 0x40;
1236  return if $chip == 3 and  $reg1 != 0x20;
1237  $reg1 = i2c_smbus_read_byte_data($file,0x4a);
1238  @res = (8);
1239  push @res, ($reg1 & 0x07) + 0x48 unless $reg1 & 0x08;
1240  push @res, (($reg1 & 0x80) >> 4) + 0x48 unless $reg1 & 0x80;
1241  return @res;
1242}
1243
1244# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 2 = W83783S, 3 = W83627HF)
1245# $_[1]: ISA address
1246# $_[2]: I2C file handle
1247# $_[3]: I2C address
1248sub w83781d_alias_detect
1249{
1250  my ($chip,$isa_addr,$file,$i2c_addr) = @_;
1251  my $i;
1252  my $readproc = sub { isa_read_byte $isa_addr + 5, $isa_addr + 6, @_ };
1253  return 0 unless &$readproc(0x48) == $i2c_addr;
1254  for ($i = 0x2b; $i <= 0x3d; $i ++) {
1255    return 0 unless &$readproc($i) == i2c_smbus_read_byte_data($file,$i);
1256  }
1257  return 1;
1258}
1259
1260# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 3 = W83627HF)
1261#        W83783S not on ISA bus.
1262# $_[1]: Address
1263# Returns: undef if not detected, (8) if detected.
1264sub w83781d_isa_detect
1265{
1266  my ($chip,$addr) = @_ ;
1267  my ($reg1,$reg2);
1268  my $val = inb ($addr + 1);
1269  return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or
1270            inb ($addr + 7) != $val;
1271
1272  $val = inb($addr + 5) & 0x7f;
1273  outb($addr+5,~ $val);
1274  if ((inb ($addr+5) & 0x7f) != (~ $val & 0x7f)) {
1275    outb($addr+5,$val);
1276    return;
1277  }
1278
1279  my $read_proc = sub { isa_read_byte $addr + 5, $addr + 6, @_ };
1280  $reg1 = &$read_proc(0x4e);
1281  $reg2 = &$read_proc(0x4f);
1282  return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or 
1283                (($reg1 & 0x80) == 0x80 and $reg2 == 0x5c);
1284  return unless ($reg1 & 0x07) == 0x00;
1285  $reg1 = &$read_proc(0x58) & 0xfe;
1286  return if $chip == 0 and  $reg1 != 0x10;
1287  return if $chip == 1 and  $reg1 != 0x30;
1288  return if $chip == 3 and  $reg1 != 0x20;
1289  return 8;
1290}
1291
1292# $_[0]: Chip to detect (0 = Revision 0x00, 1 = Revision 0x80)
1293# $_[1]: A reference to the file descriptor to access this chip.
1294#        We may assume an i2c_set_slave_addr was already done.
1295# $_[2]: Address
1296# Returns: undef if not detected, (6) if detected.
1297# Registers used:
1298#   0x00: Device ID
1299#   0x01: Revision ID
1300#   0x03: Configuration
1301# Mediocre detection
1302sub gl518sm_detect
1303{
1304  my $reg;
1305  my ($chip,$file,$addr) = @_;
1306  return unless i2c_smbus_read_byte_data($file,0x00) == 0x80;
1307  return unless (i2c_smbus_read_byte_data($file,0x03) & 0x80) == 0x00;
1308  $reg = i2c_smbus_read_byte_data($file,0x01);
1309  return unless ($chip == 0 and $reg == 0x00) or
1310                ($chip == 1 and $reg == 0x80);
1311  return (6);
1312}
1313
1314# $_[0]: A reference to the file descriptor to access this chip.
1315#        We may assume an i2c_set_slave_addr was already done.
1316# $_[1]: Address
1317# Returns: undef if not detected, (5) if detected.
1318# Registers used:
1319#   0x00: Device ID
1320#   0x01: Revision ID
1321#   0x03: Configuration
1322# Mediocre detection
1323sub gl520sm_detect
1324{
1325  my ($file,$addr) = @_;
1326  return unless i2c_smbus_read_byte_data($file,0x00) == 0x20;
1327  return unless (i2c_smbus_read_byte_data($file,0x03) & 0x80) == 0x00;
1328  # The line below must be better checked before I dare to use it.
1329  # return unless i2c_smbus_read_byte_data($file,0x01) == 0x00;
1330  return (5);
1331}
1332
1333# $_[0]: Chip to detect (0 = ADM9240, 1 = DS1780)
1334# $_[1]: A reference to the file descriptor to access this chip.
1335#        We may assume an i2c_set_slave_addr was already done.
1336# $_[2]: Address
1337# Returns: undef if not detected, (8) if detected.
1338# Registers used:
1339#   0x3e: Company ID
1340#   0x40: Configuration
1341#   0x48: Full I2C Address
1342# Note: Detection overrules a previous LM78 detection
1343sub adm9240_detect
1344{
1345  my $reg;
1346  my ($chip, $file,$addr) = @_;
1347  $reg = i2c_smbus_read_byte_data($file,0x3e);
1348  return unless ($chip == 0 and $reg == 0x23) or
1349                ($chip == 1 and $reg == 0xda);
1350  return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
1351  return unless i2c_smbus_read_byte_data($file,0x48) == $addr;
1352 
1353  return (8);
1354}
1355
1356# $_[0]: Chip to detect (0 = ADM1021, 1 = MAX1617, 2 = MAX1617A)
1357# $_[1]: A reference to the file descriptor to access this chip.
1358#        We may assume an i2c_set_slave_addr was already done.
1359# $_[2]: Address
1360# Returns: undef if not detected, (6) or (3) if detected.
1361# Registers used:
1362#   0xfe: Company ID
1363#   0x02: Status
1364# Note: Especially the Maxim has very bad detection; we give it a low
1365# confidence value.
1366sub adm1021_detect
1367{
1368  my $reg;
1369  my ($chip, $file,$addr) = @_;
1370  return if $chip == 0 and i2c_smbus_read_byte_data($file,0xfe) != 0x41;
1371  return if $chip == 2 and i2c_smbus_read_byte_data($file,0xfe) != 0x4d and
1372                           i2c_smbus_read_byte_data($file,0xff) != 0x01;
1373  # The remaining things are flaky at best. Perhaps something can be done
1374  # with the fact that some registers are unreadable?
1375  return if (i2c_smbus_read_byte_data($file,0x02) & 0x03) != 0;
1376  if ($chip == 1) {
1377    return (3);
1378  } else {
1379    return (6);
1380  }
1381}
1382
1383# $_[0]: Address
1384# Returns: undef if not detected, (9) if detected.
1385# Note: It is already 99% certain this chip exists if we find the PCI
1386# entry. The exact address is encoded in PCI space.
1387sub sis5595_isa_detect
1388{
1389  my ($addr) = @_;
1390  my ($adapter,$try,$local_try);
1391  my $found = 0;
1392  foreach $local_try (@pci_adapters) {
1393    if ($local_try->{procid} eq "Silicon Integrated Systems 85C503") {
1394      $try = $local_try;
1395      $found = 1;
1396      last;
1397    }
1398  }
1399  return if not $found;
1400
1401  $found = 0;
1402  foreach $adapter (@pci_list) {
1403    if ((defined($adapter->{vendid}) and 
1404         $try->{vendid} == $adapter->{vendid} and
1405         $try->{devid} == $adapter->{devid} and
1406         $try->{func} == $adapter->{func}) or
1407        (! defined($adapter->{vendid}) and
1408         $adapter->{desc} =~ /$try->{procid}/ and
1409         $try->{func} == $adapter->{func})) {
1410      $found = 1;
1411      last;
1412    }
1413  }
1414  return if not $found;
1415
1416  return 9;
1417}
1418
1419# $_[0]: A reference to the file descriptor to access this chip.
1420#        We may assume an i2c_set_slave_addr was already done.
1421# $_[1]: Address
1422# Returns: undef if not detected, (5) if detected.
1423# Registers used:
1424#   0x00-0x63: PC-100 Data and Checksum
1425sub eeprom_detect
1426{
1427  my ($file,$addr) = @_;
1428  # Check the checksum for validity (only works for PC-100 DIMMs)
1429  my $checksum = 0;
1430  for (my $i = 0; $i <= 62; $i = $i + 1) {
1431    $checksum = $checksum + i2c_smbus_read_byte_data($file,$i);
1432  }
1433  $checksum=$checksum & 255;
1434  if (i2c_smbus_read_byte_data($file,63) == $checksum) {
1435        return (8);
1436  }
1437  # Even if checksum test fails, it still may be an eeprom
1438  return (1);
1439}
1440
1441# $_[0]: A reference to the file descriptor to access this chip.
1442#        We may assume an i2c_set_slave_addr was already done.
1443# $_[1]: Address
1444# Returns: undef if not detected, (1) if detected.
1445# Detection is impossible!
1446sub ltc1710_detect
1447{
1448  return (1);
1449}
1450 
1451
1452################
1453# MAIN PROGRAM #
1454################
1455
1456# $_[0]: reference to a list of chip hashes
1457sub print_chips_report 
1458{
1459  my ($listref) = @_;
1460  my $data;
1461 
1462  foreach $data (@$listref) {
1463    my $is_i2c = exists $data->{i2c_addr};
1464    my $is_isa = exists $data->{isa_addr};
1465    print "  * ";
1466    if ($is_i2c) {
1467      printf "Bus `%s' (%s)\n", $data->{i2c_adap}, $data->{i2c_algo};
1468      printf "    Busdriver `%s', I2C address 0x%02x", 
1469             $data->{i2c_driver}, $data->{i2c_addr};
1470      if (exists $data->{i2c_sub_addrs}) {
1471        print " (and";
1472        my $sub_addr;
1473        foreach $sub_addr (@{$data->{i2c_sub_addrs}}) {
1474          printf " 0x%02x",$sub_addr;
1475        }
1476        print ")"
1477      }
1478      print "\n";
1479    }
1480    if ($is_isa) {
1481      print "    " if  $is_i2c;
1482      if ($data->{isa_addr}) {
1483        printf "ISA bus address 0x%04x (Busdriver `i2c-isa')\n", 
1484               $data->{isa_addr};
1485      } else {
1486        printf "ISA bus, undetermined address (Busdriver `i2c-isa')\n"
1487      }
1488    }
1489    printf "    Chip `%s' (confidence: %d)\n",
1490           $data->{chipname},  $data->{conf};
1491  }
1492}
1493
1494# $_[0]: 1 if ISA bus is prefered, 0 for SMBus
1495sub generate_modprobes
1496{
1497  my ($prefer_isa) = @_;
1498
1499  my ($chip,$detection,%adapters,$nr,$i,@optionlist,@probelist);
1500  my $modprobes = "";
1501  my $configfile = "";
1502
1503  # These are always needed
1504  $configfile .= "# I2C module options\n";
1505  $configfile .= "alias char-major-89 i2c-dev\n";
1506
1507  # Collect all adapters
1508  $nr = 0;
1509  $modprobes .= "# I2C adapter drivers\n";
1510  foreach $chip (@chips_detected) {
1511    foreach $detection (@{$chip->{detected}}) {
1512      %adapters->{$detection->{i2c_driver}} = $nr ++
1513            if exists $detection->{i2c_driver} and 
1514               not exists %adapters->{$detection->{i2c_driver}} and
1515               not (exists $detection->{isa_addr} and $prefer_isa);
1516      %adapters->{"i2c-isa"} = $nr ++ 
1517            if exists $detection->{isa_addr} and 
1518               not exists %adapters->{"i2c-isa"} and
1519               not (exists $detection->{i2c_driver} and not $prefer_isa);
1520    }
1521  }
1522  for ($i = 0; $i < $nr; $i ++) {
1523    foreach $detection (keys %adapters) {
1524      $modprobes .= "modprobe $detection\n", last 
1525                 if $adapters{$detection} == $i;
1526    }
1527  }
1528
1529  # Now determine the chip probe lines
1530  $modprobes .= "# I2C chip drivers\n";
1531  foreach $chip (@chips_detected) {
1532    next if not @{$chip->{detected}};
1533    $modprobes .= "modprobe $chip->{driver}\n";
1534    @optionlist = ();
1535    @probelist = ();
1536
1537    # Handle detects out-of-range
1538    foreach $detection (@{$chip->{detected}}) {
1539      push @probelist, %adapters->{$detection->{i2c_driver}},
1540                       $detection->{i2c_addr}
1541           if exists $detection->{i2c_driver} and
1542              exists %adapters->{$detection->{i2c_driver}} and
1543              exists $detection->{i2c_extra};
1544      push @probelist, -1, $detection->{isa_addr}
1545           if exists $detection->{isa_addr} and
1546              exists %adapters->{"i2c-isa"} and
1547              exists $detection->{isa_extra};
1548    }
1549
1550    # Handle misdetects
1551    foreach $detection (@{$chip->{misdetected}}) {
1552      push @optionlist, %adapters->{$detection->{i2c_driver}},
1553                       $detection->{i2c_addr}
1554           if exists $detection->{i2c_driver} and
1555              exists %adapters->{$detection->{i2c_driver}};
1556      push @optionlist, -1, $detection->{isa_addr}
1557           if exists $detection->{isa_addr} and
1558              exists %adapters->{"i2c-isa"};
1559    }
1560
1561    # Handle aliases
1562    foreach $detection (@{$chip->{detected}}) {
1563      if (exists $detection->{i2c_driver} and 
1564          exists $detection->{isa_addr} and
1565          exists %adapters->{$detection->{i2c_driver}} and
1566          exists %adapters->{"i2c-isa"}) {
1567        if ($prefer_isa) {
1568          push @optionlist,%adapters->{$detection->{i2c_driver}},
1569                           $detection->{i2c_addr};
1570        } else {
1571          push @optionlist, -1, $detection->{isa_addr}
1572        }
1573      }
1574    }
1575
1576    next if not (@probelist or @optionlist);
1577    $configfile .= "options $chip->{driver}";
1578    $configfile .= sprintf " ignore=%d,0x%02x",shift @optionlist, 
1579                                               shift @optionlist
1580                  if @optionlist;
1581    $configfile .= sprintf ",%d,0x%02x",shift @optionlist, shift @optionlist
1582                  while @optionlist;
1583    $configfile .= sprintf " probe=%d,0x%02x",shift @probelist,
1584                                              shift @probelist
1585                  if @probelist;
1586    $configfile .= sprintf ",%d,0x%02x",shift @probelist, shift @probelist
1587                  while @probelist;
1588    $configfile .= "\n";
1589  }
1590
1591  return ($modprobes,$configfile);
1592 
1593}
1594
1595sub main
1596{
1597  my (@adapters,$res,$did_adapter_detection,$detect_others,$adapter);
1598
1599  initialize_proc_pci;
1600  initialize_modules_list;
1601
1602  print " This program will help you to determine which I2C/SMBus modules you ",
1603        "need to\n",
1604        " load to use lm_sensors most effectively.\n";
1605  print " You need to have done a `make install', issued a `depmod -a' and ",
1606        "made sure\n",
1607        " `/etc/conf.modules' (or `/etc/modules.conf') contains the ",
1608        "appropriate\n",
1609        " module path before you can use some functions of this utility. ",
1610        "Read\n",
1611        " doc/modules for more information.\n";
1612  print " Also, you need to be `root', or at least have access to the ",
1613        "/dev/i2c-* files\n",
1614        " for some things. You can use prog/mkdev/mkdev.sh to create these ",
1615        "/dev files\n",
1616        " if you do not have them already.\n\n";
1617
1618  print " We can start with probing for (PCI) I2C or SMBus adapters.\n";
1619  print " You do not need any special privileges for this.\n";
1620  print " Do you want to probe now? (YES/no): ";
1621  @adapters = adapter_pci_detection
1622                        if ($did_adapter_detection = not <STDIN> =~ /\s*[Nn]/);
1623
1624  print "\n";
1625
1626  if (not $did_adapter_detection) {
1627    print " As you skipped adapter detection, we will only scan already ",
1628          "loaded adapter\n",
1629          " modules. You can still be prompted for non-detectable adapters.\n",
1630          " Do you want to? (yes/NO): ";
1631    $detect_others = <STDIN> =~ /^\s*[Yy]/;
1632  } elsif ($> != 0) {
1633    print " As you are not root, we can't load adapter modules. We will only ",
1634          "scan\n",
1635          " already loaded adapters.\n";
1636    $detect_others = 0;
1637  } else {
1638    print " We will now try to load each adapter module in turn.\n";
1639    foreach $adapter (@adapters) {
1640      if (contains $adapter, @modules_list) {
1641        print "Module `$adapter' already loaded.\n";
1642      } else {
1643        print "Load `$adapter'? (YES/no): ";
1644        unless (<STDIN> =~ /^\s*[Nn]/) {
1645          if (system ("modprobe", $adapter)) {
1646            print "Loading failed ($!)... skipping.\n";
1647          } else {
1648            print "Module loaded succesfully.\n";
1649          }
1650        }
1651      }
1652    }
1653    print " Do you now want to be prompted for non-detectable adapters? ",
1654          "(yes/NO): ";
1655    $detect_others = <STDIN> =~ /^\s*[Yy]/ ;
1656  }
1657
1658  if ($detect_others) {
1659    foreach $adapter (@undetectable_adapters) {
1660      print "Load `$adapter'? (YES/no): ";
1661      unless (<STDIN> =~ /^\s*[Nn]/) {
1662        if (system ("modprobe", $adapter)) {
1663          print "Loading failed ($!)... skipping.\n";
1664        } else {
1665          print "Module loaded succesfully.\n";
1666        }
1667      }
1668    }
1669  }
1670
1671  print " To continue, we need module `i2c-dev' to be loaded.\n";
1672  if (contains "i2c-dev", @modules_list) {
1673    print "i2c-dev is already loaded.\n";
1674  } else {
1675    if ($> != 0) {
1676      print " i2c-dev is not loaded. As you are not root, we will just hope ",
1677            "you edited\n",
1678            " `/etc/conf.modules' (or `/etc/modules.conf') for automatic ",
1679            "loading of\n",
1680            " this module. If not, you won't be able to open any /dev/i2c-* ",
1681            "file.\n";
1682    } else {
1683      print " i2c-dev is not loaded. Do you want to load it now? (YES/no): ";
1684      if (<STDIN> =~ /^\s*[Nn]/) {
1685        print " Well, you will know best. We will just hope you edited ",
1686              "`/etc/conf.modules'\n",
1687              " (or `/etc/modules.conf') for automatic loading of this ",
1688              "module. If not,",
1689              " you won't be able to open any /dev/i2c-* file.\n";
1690      } elsif (system "modprobe","i2c-dev") {
1691        print " Loading failed ($!), aborting.\n";
1692        exit;
1693      } else {
1694        print " Module loaded succesfully.\n";
1695      }
1696    }
1697  }
1698
1699  print "\n We are now going to do the adapter probings. Some adapters may ",
1700        "hang halfway\n",
1701        " through; we can't really help that. Also, some chips will be double ",
1702        "detected;\n",
1703        " we choose the one with the highest confidence value in that case.\n",
1704        " If you found that the adapter hung after probing a certain address, ",
1705        "you can\n",
1706        " specify that address to remain unprobed. If you have a PIIX4, that ",
1707        "often\n",
1708        " includes addresses 0x69 and/or 0x6a.\n";
1709
1710  my ($inp,@not_to_scan,$inp2);
1711  open INPUTFILE,"/proc/bus/i2c" or die "Couldn't open /proc/bus/i2c?!?";
1712  while (<INPUTFILE>) {
1713    print "\n";
1714    my ($dev_nr,$adap,$algo) = /^i2c-(\S+)\s+\S+\s+(.*?)\s*\t\s*(.*?)\s+$/;
1715    print "Next adapter: $adap ($algo)\n";
1716    print "Do you want to scan it? (YES/no/selectively): ";
1717   
1718    $inp = <STDIN>;
1719    @not_to_scan=();
1720    if ($inp =~ /^\s*[Ss]/) {
1721      print "Please enter one or more addresses not to scan. Separate them ",
1722            "with comma's.\n",
1723            "You can specify a range by using dashes. Addresses may be ",
1724            "decimal (like 54)\n",
1725            "or hexadecimal (like 0x33).\n",
1726            "Addresses: ";
1727      $inp2 = <STDIN>;
1728      chop $inp2;
1729      @not_to_scan = parse_not_to_scan 0,0x7f,$inp2;
1730    }
1731    scan_adapter $dev_nr, $adap, $algo, find_adapter_driver($adap,$algo),
1732                 \@not_to_scan   unless $inp =~ /^\s*[Nn]/;
1733  }
1734
1735  print "\n Some chips are also accessible through the ISA bus. ISA probes ",
1736        "are\n",
1737        " typically a bit more dangerous, as we have to write to I/O ports ",
1738        "to do\n",
1739        " this. ";
1740  if ($> != 0) {
1741    print "As you are not root, we shall skip this step.\n";
1742  } else {
1743    print " Do you want to scan the ISA bus? (YES/no): ";
1744    if (not <STDIN> =~ /^\s*[Nn]/) {
1745      initialize_ioports or die "Sorry, can't access /dev/port ($!)?!?";
1746      scan_isa_bus;
1747    }
1748  }
1749
1750  print "\n Now follows a summary of the probes I have just done.\n";
1751  print " Just press ENTER to continue: ";
1752  <STDIN>;
1753
1754  my ($chip,$data);
1755  foreach $chip (@chips_detected) {
1756    print "\nDriver `$$chip{driver}' ";
1757    if (@{$$chip{detected}}) {
1758      if (@{$$chip{misdetected}}) {
1759        print "(should be inserted but causes problems):\n";
1760      } else {
1761        print "(should be inserted):\n";
1762      }
1763    } else {
1764      if (@{$$chip{misdetected}}) {
1765        print "(may not be inserted):\n";
1766      } else {
1767        print "(should not be inserted, but is harmless):\n";
1768      }
1769    }
1770    if (@{$$chip{detected}}) {
1771      print "  Detects correctly:\n";
1772      print_chips_report $chip->{detected};
1773    }
1774    if (@{$$chip{misdetected}}) {
1775      print "  Misdetects:\n";
1776      print_chips_report $chip->{misdetected};
1777    }
1778  }
1779
1780  print "\n\n",
1781        " I will now generate the commands needed to load the I2C modules.\n",
1782        " Sometimes, a chip is available both through the ISA bus and an ",
1783        "I2C bus.\n",
1784        " ISA bus access is faster, but you need to load an additional driver ",
1785        "module\n",
1786        " for it. If you have the choice, do you want to use the ISA bus or ",
1787        "the\n",
1788        " I2C/SMBus (ISA/smbus)? ";
1789  my $use_isa = not <STDIN> =~ /\s*[Ss]/;
1790     
1791  my ($modprobes,$configfile) = generate_modprobes $use_isa;
1792  print "\nTo load everything that is needed, add this to some /etc/rc* ",
1793        "file:\n\n";
1794  print "#----cut here----\n";
1795  print $modprobes;
1796  print "#----cut here----\n";
1797  print "\nTo make the sensors modules behave correctly, add these lines to ",
1798        "either\n",
1799        "/etc/modules.conf or /etc/conf.modules:\n\n";
1800  print "#----cut here----\n";
1801  print $configfile;
1802  print "#----cut here----\n";
1803 
1804}
1805
1806main;
Note: See TracBrowser for help on using the browser.