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

Revision 720, 68.9 KB (checked in by frodo, 13 years ago)

sensors-detect should cope better now with adapters with multiple

busses

The changes are large and tricky, so it is almost certain there are
many bugs. Please run sensors-detect and tell me whether it works
correctly or not.

All changes are in the routines that print the modprobe statements at
the end, so if it fails, it will fail there.

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