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

Revision 323, 54.3 KB (checked in by frodo, 14 years ago)

Finished renaming of detect.pl

* Either Phil had not done a 'cvs update', or I forgot a 'cvs commit'; anyway,

the last changes to detect.pl have been ported to sensors-detect.

* Added a rule to the Makefile fragment to install it in $(SBINDIR).
* Added SBINDIR to the main Makefile.
* Deleted detect.pl

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