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

Revision 533, 59.3 KB (checked in by mds, 14 years ago)

(mds) add support for TI THMC10 to the adm1021 driver.

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