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

Revision 303, 54.4 KB (checked in by frodo, 14 years ago)

Minor fixes

* No more redefined complaints of MODULE_* symbols for 2.0 kernels

This was introduced by the last archive of Simon

* Correct load order of adapters in detect script modprobe report

You can't assume things come out of a hash in the same order as you
put them in, of course :-(

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