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

Revision 2439, 143.8 KB (checked in by khali, 9 years ago)

Detect LM92, LM76, MAX6633, MAX6634, MAX6635.

  • 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 -w
2
3#
4#    sensors-detect - Detect PCI bus and chips
5#    Copyright (C) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>
6#    Copyright (C) 2000 - 2004  The lm_sensors team
7#
8#    This program is free software; you can redistribute it and/or modify
9#    it under the terms of the GNU General Public License as published by
10#    the Free Software Foundation; either version 2 of the License, or
11#    (at your option) any later version.
12#
13#    This program is distributed in the hope that it will be useful,
14#    but WITHOUT ANY WARRANTY; without even the implied warranty of
15#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16#    GNU General Public License for more details.
17#
18#    You should have received a copy of the GNU General Public License
19#    along with this program; if not, write to the Free Software
20#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21#
22
23# TODO: Better handling of chips with several addresses
24
25# A Perl wizard really ought to look upon this; the PCI and I2C stuff should
26# each be put in a separate file, using modules and packages. That is beyond
27# me.
28
29require 5.004;
30
31use strict;
32use Fcntl;
33use POSIX;
34
35# Just in case a root user doesn't have /sbin in his/her path for some reason
36# (was seen once)
37$ENV{PATH} = '/sbin:'.$ENV{PATH}
38        unless $ENV{PATH} =~ m,(^|:)/sbin/?(:|$),;
39# Same for /usr/local/sbin since we need i2cdetect which is installed there
40# by default (reported by Lennard Klein)
41$ENV{PATH} = '/usr/local/sbin:'.$ENV{PATH}
42        unless $ENV{PATH} =~ m,(^|:)/usr/local/sbin/?(:|$),;
43
44#########################
45# CONSTANT DECLARATIONS #
46#########################
47
48use vars qw(@pci_adapters @chip_ids @superio_ids);
49
50# This is the list of SMBus or I2C adapters we recognize by their PCI
51# signature. This is an easy and fast way to determine which SMBus or I2C
52# adapters should be present.
53# Each entry must have a vendid (Vendor ID), devid (Device ID), func (PCI
54# Function) and procid (string as appears in /proc/pci; see linux/driver/pci,
55# either pci.c or oldproc.c). If no driver is written yet, set the
56# driver (Driver Name) field to "to-be-written".
57# The match (Match Description) field should
58# contain a function which returns zero if its two parameter matches
59# the text as it would appear in /proc/bus/i2c.
60@pci_adapters = ( 
61     { 
62       vendid => 0x8086,
63       devid  => 0x7113,
64       func => 3,
65       procid => "Intel 82371AB PIIX4 ACPI",
66       driver => "i2c-piix4",
67       match => sub { $_[0] =~ /^SMBus PIIX4 adapter at / },
68     } , 
69     { 
70       vendid => 0x8086,
71       devid  => 0x719b,
72       func => 3,
73       procid => "Intel 82443MX Mobile",
74       driver => "i2c-piix4",
75       match => sub { $_[0] =~ /^SMBus PIIX4 adapter at / },
76     } , 
77     { 
78       vendid => 0x8086,
79       devid  => 0x2413,
80       func => 3,
81       procid => "Intel 82801AA ICH",
82       driver => "i2c-i801",
83       match => sub { $_[0] =~ /^SMBus I801 adapter at [0-9,a-f]{4}/ },
84     } , 
85     { 
86       vendid => 0x8086,
87       devid  => 0x2423,
88       func => 3,
89       procid => "Intel 82801AB ICH0",
90       driver => "i2c-i801",
91       match => sub { $_[0] =~ /^SMBus I801 adapter at [0-9,a-f]{4}/ },
92     } , 
93     { 
94       vendid => 0x8086,
95       devid  => 0x2443,
96       func => 3,
97       procid => "Intel 82801BA ICH2",
98       driver => "i2c-i801",
99       match => sub { $_[0] =~ /^SMBus I801 adapter at [0-9,a-f]{4}/ },
100     } , 
101     { 
102       vendid => 0x8086,
103       devid  => 0x2483,
104       func => 3,
105       procid => "Intel 82801CA/CAM ICH3",
106       driver => "i2c-i801",
107       match => sub { $_[0] =~ /^SMBus I801 adapter at [0-9,a-f]{4}/ },
108     } , 
109     { 
110       vendid => 0x8086,
111       devid  => 0x24C3,
112       func => 3,
113       procid => "Intel 82801DB ICH4",
114       driver => "i2c-i801",
115       match => sub { $_[0] =~ /^SMBus I801 adapter at [0-9,a-f]{4}/ },
116     } , 
117     { 
118       vendid => 0x8086,
119       devid  => 0x24D3,
120       func => 3,
121       procid => "Intel 82801EB ICH5",
122       driver => "i2c-i801",
123       match => sub { $_[0] =~ /^SMBus I801 adapter at [0-9,a-f]{4}/ },
124     } , 
125     { 
126       vendid => 0x1106,
127       devid  => 0x3040,
128       func => 3,
129       procid => "VIA Technologies VT82C586B Apollo ACPI",
130       driver => "i2c-via",
131       match => sub { $_[0] =~ /^VIA i2c/ },
132     } ,
133     { 
134       vendid => 0x1106,
135       devid  => 0x3050,
136       func => 3,
137       procid => "VIA Technologies VT82C596 Apollo ACPI",
138       driver => "i2c-viapro",
139       match => sub { $_[0] =~ /^SMBus Via Pro adapter at/ },
140     } ,
141     { 
142       vendid => 0x1106,
143       devid  => 0x3051,
144       func => 3,
145       procid => "VIA Technologies VT82C596B ACPI",
146       driver => "i2c-viapro",
147       match => sub { $_[0] =~ /^SMBus Via Pro adapter at/ },
148     } ,
149     { 
150       vendid => 0x1106,
151       devid  => 0x3057,
152       func => 4,
153       procid => "VIA Technologies VT82C686 Apollo ACPI",
154       driver => "i2c-viapro",
155       match => sub { $_[0] =~ /^SMBus Via Pro adapter at/ },
156     } ,
157     { 
158       vendid => 0x1106,
159       devid  => 0x3074,
160       func => 0,
161       procid => "VIA Technologies VT8233 VLink South Bridge",
162       driver => "i2c-viapro",
163       match => sub { $_[0] =~ /^SMBus Via Pro adapter at/ },
164     } ,
165     { 
166       vendid => 0x1106,
167       devid  => 0x3147,
168       func => 0,
169       procid => "VIA Technologies VT8233A South Bridge",
170       driver => "i2c-viapro",
171       match => sub { $_[0] =~ /^SMBus Via Pro adapter at/ },
172     } ,
173     { 
174       vendid => 0x1106,
175       devid  => 0x3177,
176       func => 0,
177       procid => "VIA Technologies VT8233A/8235 South Bridge",
178       driver => "i2c-viapro",
179       match => sub { $_[0] =~ /^SMBus Via Pro adapter at/ },
180     } ,
181     {
182       vendid => 0x1106,
183       devid  => 0x3227,
184       func => 0,
185       procid => "VIA Technologies VT8237 South Bridge",
186       driver => "i2c-viapro",
187       match => sub { $_[0] =~ /^SMBus Via Pro adapter at/ },
188     } ,
189     { 
190       vendid => 0x1106,
191       devid  => 0x8235,
192       func => 4,
193       procid => "VIA Technologies VT8231 South Bridge",
194       driver => "i2c-viapro",
195       match => sub { $_[0] =~ /^SMBus Via Pro adapter at/ },
196     } ,
197     {
198       vendid => 0x1039,
199       devid  => 0x5597,
200       func => 0,
201       procid => "Silicon Integrated Systems SIS5581/5582/5597/5598 (To be written - Do not use 5595 drivers)",
202       driver => "to-be-written",
203       match => sub { 0 },
204     } ,
205     {
206       vendid => 0x1039,
207       devid  => 0x5598,
208       func => 0,
209       procid => "Silicon Integrated Systems SIS5598 (To be written - Do not use 5595 drivers)",
210       driver => "to-be-written",
211       match => sub { 0 },
212     } ,
213     {
214       vendid => 0x1039,
215       devid  => 0x0540,
216       func => 0,
217       procid => "Silicon Integrated Systems SIS540 (To be written - Do not use 5595 drivers)",
218       driver => "to-be-written",
219       match => sub { 0 },
220     } ,
221     {
222       vendid => 0x1039,
223       devid  => 0x0630,
224       func => 0,
225       procid => "Silicon Integrated Systems SIS630",
226       driver => "i2c-sis630",
227       match => sub { $_[0] =~ /^SMBus SIS630 adapter at [0-9,a-f]{4}/ },
228     } ,
229     {
230       vendid => 0x1039,
231       devid  => 0x0730,
232       func => 0,
233       procid => "Silicon Integrated Systems SIS730",
234       driver => "i2c-sis630",
235       match => sub { $_[0] =~ /^SMBus SIS630 adapter at [0-9,a-f]{4}/ },
236     } ,
237#
238# Both Ali chips below have same PCI ID. Can't be helped. Only one should load.
239#
240     {
241       vendid => 0x10b9,
242       devid => 0x7101,
243       func => 0,
244       procid => "Acer Labs 1533/1543",
245       driver => "i2c-ali15x3",
246       match => sub { $_[0] =~ /^SMBus ALI15X3 adapter at/ },
247     },
248     {
249       vendid => 0x10b9,
250       devid => 0x7101,
251       func => 0,
252       procid => "Acer Labs 1535",
253       driver => "i2c-ali1535",
254       match => sub { $_[0] =~ /^SMBus ALI1535 adapter at/ },
255     },
256     { 
257       vendid => 0x106b,
258       devid  => 0x000e,
259       func => 0,
260       procid => "Apple Computer Inc. Hydra Mac I/O",
261       driver => "i2c-hydra",
262       match => sub { $_[0] =~ /^Hydra i2c/ },
263     },
264     { 
265       vendid => 0x1022,
266       devid  => 0x740b,
267       func => 3,
268       procid => "AMD-756 Athlon ACPI",
269       driver => "i2c-amd756",
270       match => sub { $_[0] =~ /^SMBus AMD756 adapter at [0-9,a-f]{4}/ },
271     },
272     { 
273       vendid => 0x1022,
274       devid  => 0x7413,
275       func => 3,
276       procid => "AMD-766 Athlon ACPI",
277       driver => "i2c-amd756",
278       match => sub { $_[0] =~ /^SMBus AMD766 adapter at [0-9,a-f]{4}/ },
279     },
280     { 
281       vendid => 0x1022,
282       devid  => 0x7443,
283       func => 3,
284       procid => "AMD-768 System Management",
285       driver => "i2c-amd756",
286       match => sub { $_[0] =~ /^SMBus AMD768 adapter at [0-9,a-f]{4}/ },
287     },
288     { 
289       vendid => 0x1022,
290       devid  => 0x746b,
291       func => 3,
292       procid => "AMD-8111 ACPI",
293       driver => "i2c-amd756",
294       match => sub { $_[0] =~ /^SMBus AMD8111 adapter at [0-9,a-f]{4}/ },
295     },
296     { 
297       vendid => 0x1022,
298       devid  => 0x746a,
299       func => 2,
300       procid => "AMD-8111 SMBus 2.0",
301       driver => "i2c-amd8111",
302       match => sub { $_[0] =~ /^SMBus2 AMD8111 adapter at [0-9,a-f]{4}/ },
303     },
304     {
305       vendid => 0x102b,
306       devid  => 0x0519,
307       func   => 0,
308       procid => "MGA 2064W [Millennium]",
309       driver => "i2c-matroxfb",
310       match  => sub { $_[0] =~ /^DDC:fb[0-9]{1,2}/ },
311     },
312     {
313       vendid => 0x102b,
314       devid  => 0x051a,
315       func   => 0,
316       procid => "MGA 1064SG [Mystique]",
317       driver => "i2c-matroxfb",
318       match  => sub { $_[0] =~ /^DDC:fb[0-9]{1,2}/ },
319     },
320     {
321       vendid => 0x102b,
322       devid  => 0x051b,
323       func   => 0,
324       procid => "MGA 2164W [Millennium II]",
325       driver => "i2c-matroxfb",
326       match  => sub { $_[0] =~ /^DDC:fb[0-9]{1,2}/ },
327     },
328     {
329       vendid => 0x102b,
330       devid  => 0x051e,
331       func   => 0,
332       procid => "MGA 1064SG [Mystique] AGP",
333       driver => "i2c-matroxfb",
334       match  => sub { $_[0] =~ /^DDC:fb[0-9]{1,2}/ },
335     },
336     {
337       vendid => 0x102b,
338       devid  => 0x051f,
339       func   => 0,
340       procid => "MGA 2164W [Millennium II] AGP",
341       driver => "i2c-matroxfb",
342       match  => sub { $_[0] =~ /^DDC:fb[0-9]{1,2}/ },
343     },
344     {
345       vendid => 0x102b,
346       devid  => 0x1000,
347       func   => 0,
348       procid => "MGA G100 [Productiva]",
349       driver => "i2c-matroxfb",
350       match  => sub { $_[0] =~ /^DDC:fb[0-9]{1,2}/ },
351     },
352     {
353       vendid => 0x102b,
354       devid  => 0x1001,
355       func   => 0,
356       procid => "MGA G100 [Productiva] AGP",
357       driver => "i2c-matroxfb",
358       match  => sub { $_[0] =~ /^DDC:fb[0-9]{1,2}/ },
359     },
360     {
361       vendid => 0x102b,
362       devid  => 0x0520,
363       func   => 0,
364       procid => "MGA G200",
365       driver => "i2c-matroxfb",
366       match  => sub { $_[0] =~ /^DDC:fb[0-9]{1,2}/ },
367     },
368     {
369       vendid => 0x102b,
370       devid  => 0x0521,
371       func   => 0,
372       procid => "MGA G200 AGP",
373       driver => "i2c-matroxfb",
374       match  => sub { $_[0] =~ /^DDC:fb[0-9]{1,2}/ },
375     },
376     {
377       vendid => 0x102b,
378       devid  => 0x0525,
379       func   => 0,
380       procid => "MGA G400 AGP",
381       driver => "i2c-matroxfb",
382       match  => sub { $_[0] =~ /^(DDC,MAVEN):fb[0-9]{1,2}/ },
383     },
384     {
385       vendid => 0x121a,
386       devid  => 0x0005,
387       func   => 0,
388       procid => "3Dfx Voodoo3",
389       driver => "i2c-voodoo3",
390       match  => sub { $_[0] =~ /Banshee adapter/ },
391     },
392     {
393       vendid => 0x121a,
394       devid  => 0x0003,
395       func   => 0,
396       procid => "3Dfx Voodoo Banshee",
397       driver => "i2c-voodoo3",
398       match  => sub { $_[0] =~ /Banshee adapter/ },
399     },
400     { 
401       vendid => 0x8086,
402       devid  => 0x7121,
403       func => 0,
404       procid => "Intel 82810 GMCH",
405       driver => "i2c-i810",
406       match => sub { $_[0] =~ /^I810/ },
407     } , 
408     { 
409       vendid => 0x8086,
410       devid  => 0x7123,
411       func => 0,
412       procid => "Intel 82810-DC100 GMCH",
413       driver => "i2c-i810",
414       match => sub { $_[0] =~ /^I810/ },
415     } , 
416     { 
417       vendid => 0x8086,
418       devid  => 0x7125,
419       func => 0,
420       procid => "Intel 82810E GMCH",
421       driver => "i2c-i810",
422       match => sub { $_[0] =~ /^I810/ },
423     } , 
424     { 
425       vendid => 0x8086,
426       devid  => 0x1132,
427       func => 0,
428       procid => "Intel 82815 GMCH",
429       driver => "i2c-i810",
430       match => sub { $_[0] =~ /^I810/ },
431     } , 
432     { 
433       vendid => 0x12d2,
434       devid  => 0x0018,
435       func => 0,
436       procid => "RIVA 128",
437       driver => "rivatv",
438       match => sub { $_[0] =~ /^NVIDIA display/ },
439     } , 
440     { 
441       vendid => 0x10de,
442       devid  => 0x0020,
443       func => 0,
444       procid => "RIVA TNT",
445       driver => "rivatv",
446       match => sub { $_[0] =~ /^NVIDIA display/ },
447     } , 
448     { 
449       vendid => 0x10de,
450       devid  => 0x0028,
451       func => 0,
452       procid => "RIVA TNT2",
453       driver => "rivatv",
454       match => sub { $_[0] =~ /^NVIDIA display/ },
455     } , 
456     { 
457       vendid => 0x10de,
458       devid  => 0x0029,
459       func => 0,
460       procid => "RIVA UTNT2",
461       driver => "rivatv",
462       match => sub { $_[0] =~ /^NVIDIA display/ },
463     } , 
464     { 
465       vendid => 0x10de,
466       devid  => 0x002c,
467       func => 0,
468       procid => "RIVA VTNT2",
469       driver => "rivatv",
470       match => sub { $_[0] =~ /^NVIDIA display/ },
471     } , 
472     { 
473       vendid => 0x10de,
474       devid  => 0x002d,
475       func => 0,
476       procid => "RIVA UVTNT2",
477       driver => "rivatv",
478       match => sub { $_[0] =~ /^NVIDIA display/ },
479     } , 
480     { 
481       vendid => 0x10de,
482       devid  => 0x00a0,
483       func => 0,
484       procid => "RIVA ITNT2",
485       driver => "rivatv",
486       match => sub { $_[0] =~ /^NVIDIA display/ },
487     } , 
488     { 
489       vendid => 0x10de,
490       devid  => 0x0100,
491       func => 0,
492       procid => "GeForce SDR",
493       driver => "rivatv",
494       match => sub { $_[0] =~ /^NVIDIA display/ },
495     } , 
496     { 
497       vendid => 0x10de,
498       devid  => 0x0101,
499       func => 0,
500       procid => "GeForce DDR",
501       driver => "rivatv",
502       match => sub { $_[0] =~ /^NVIDIA display/ },
503     } , 
504     { 
505       vendid => 0x10de,
506       devid  => 0x0102,
507       func => 0,
508       procid => "Quadro",
509       driver => "rivatv",
510       match => sub { $_[0] =~ /^NVIDIA display/ },
511     } , 
512     { 
513       vendid => 0x10de,
514       devid  => 0x0150,
515       func => 0,
516       procid => "GeForce2 GTS",
517       driver => "rivatv",
518       match => sub { $_[0] =~ /^NVIDIA display/ },
519     } , 
520     { 
521       vendid => 0x10de,
522       devid  => 0x0110,
523       func => 0,
524       procid => "GeForce2 MX",
525       driver => "rivatv",
526       match => sub { $_[0] =~ /^NVIDIA display/ },
527     } , 
528     { 
529       vendid => 0x10de,
530       devid  => 0x0111,
531       func => 0,
532       procid => "GeForce2 MX2",
533       driver => "rivatv",
534       match => sub { $_[0] =~ /^NVIDIA display/ },
535     } , 
536     { 
537       vendid => 0x10de,
538       devid  => 0x0113,
539       func => 0,
540       procid => "Quadro2 MXR",
541       driver => "rivatv",
542       match => sub { $_[0] =~ /^NVIDIA display/ },
543     } , 
544     { 
545       vendid => 0x10de,
546       devid  => 0x0151,
547       func => 0,
548       procid => "GeForce2 GTS2",
549       driver => "rivatv",
550       match => sub { $_[0] =~ /^NVIDIA display/ },
551     } , 
552     { 
553       vendid => 0x10de,
554       devid  => 0x0152,
555       func => 0,
556       procid => "GeForce2 Ultra",
557       driver => "rivatv",
558       match => sub { $_[0] =~ /^NVIDIA display/ },
559     } , 
560     { 
561       vendid => 0x10de,
562       devid  => 0x0153,
563       func => 0,
564       procid => "Quadro2 Pro",
565       driver => "rivatv",
566       match => sub { $_[0] =~ /^NVIDIA display/ },
567     } , 
568     { 
569       vendid => 0x10de,
570       devid  => 0x0312,
571       func => 0,
572       procid => "GeForce FX 5600",
573       driver => "rivatv",
574       match => sub { $_[0] =~ /^NVIDIA display/ },
575     } , 
576     { 
577       vendid => 0x10de,
578       devid  => 0x01b4,
579       func => 1,
580       procid => "nVidia nForce SMBus",
581       driver => "i2c-amd756",
582       match => sub { $_[0] =~ /^SMBus nVidia nForce adapter at [0-9,a-f]{4}/ },
583     } , 
584     { 
585       vendid => 0x10de,
586       devid  => 0x0064,
587       func => 1,
588       procid => "nVidia Corporation nForce2 SMBus (MCP)",
589       driver => "i2c-nforce2",
590       match => sub { $_[0] =~ /^SMBus nForce2 adapter at / },
591     } , 
592     { 
593       vendid => 0x1166,
594       devid  => 0x0200,
595       func => 0,
596       procid => "ServerWorks OSB4 South Bridge",
597       driver => "i2c-piix4",
598       match => sub { $_[0] =~ /^SMBus PIIX4 adapter at / },
599     } , 
600     { 
601       vendid => 0x1055,
602       devid  => 0x9463,
603       func => 0,
604       procid => "SMSC Victory66 South Bridge",
605       driver => "i2c-piix4",
606       match => sub { $_[0] =~ /^SMBus PIIX4 adapter at / },
607     } , 
608     { 
609       vendid => 0x1166,
610       devid  => 0x0201,
611       func => 0,
612       procid => "ServerWorks CSB5 South Bridge",
613       driver => "i2c-piix4",
614       match => sub { $_[0] =~ /^SMBus PIIX4 adapter at / },
615     } , 
616     { 
617       vendid => 0x1166,
618       devid  => 0x0203,
619       func => 0,
620       procid => "ServerWorks CSB6 South Bridge",
621       driver => "i2c-piix4",
622       match => sub { $_[0] =~ /^SMBus PIIX4 adapter at / },
623     } , 
624     { 
625       vendid => 0x1283,
626       devid  => 0x8172,
627       func => 0,
628       procid => "ITE 8172G MIPS/SH4 Support Chip",
629       driver => "i2c-adap-ite",
630       match => sub { $_[0] =~ /^ITE IIC adapter/ },
631     } , 
632     { 
633       vendid => 0x5333,
634       devid  => 0x8A20,
635       func => 0,
636       procid => "S3 Savage 3D",
637       driver => "to-be-written",
638       match => sub { 0 },
639     } , 
640     { 
641       vendid => 0x5333,
642       devid  => 0x8A21,
643       func => 0,
644       procid => "S3 Savage 3D MV",
645       driver => "to-be-written",
646       match => sub { 0 },
647     } , 
648     { 
649       vendid => 0x5333,
650       devid  => 0x8A22,
651       func => 0,
652       procid => "S3 Savage 4",
653       driver => "i2c-savage4",
654       match => sub { $_[0] =~ /Savage4 adapter/ },
655     } , 
656     { 
657       vendid => 0x5333,
658       devid  => 0x9102,
659       func => 0,
660       procid => "S3 Savage 2000",
661       driver => "i2c-savage4",
662       match => sub { $_[0] =~ /Savage4 adapter/ },
663     } , 
664     { 
665       vendid => 0x5333,
666       devid  => 0x8A25,
667       func => 0,
668       procid => "S3 ProSavage PM",
669       driver => "to-be-written",
670       match => sub { $_[0] =~ /^dontmatchthis/ },
671     } , 
672     { 
673       vendid => 0x5333,
674       devid  => 0x8A26,
675       func => 0,
676       procid => "S3 ProSavage KM",
677       driver => "to-be-written",
678       match => sub { 0 },
679     } , 
680     { 
681       vendid => 0x5333,
682       devid  => 0x8C10,
683       func => 0,
684       procid => "S3 Savage MX MV",
685       driver => "to-be-written",
686       match => sub { 0 },
687     } , 
688     { 
689       vendid => 0x5333,
690       devid  => 0x8C11,
691       func => 0,
692       procid => "S3 Savage MX",
693       driver => "to-be-written",
694       match => sub { 0 },
695     } , 
696     { 
697       vendid => 0x5333,
698       devid  => 0x8C12,
699       func => 0,
700       procid => "S3 Savage IX MV",
701       driver => "to-be-written",
702       match => sub { 0 },
703     } , 
704     { 
705       vendid => 0x5333,
706       devid  => 0x8C13,
707       func => 0,
708       procid => "S3 Savage IX",
709       driver => "to-be-written",
710       match => sub { 0 },
711     } , 
712);
713
714# The following entries used to appear directly in @pci_adapters.
715# Because of the tendency of SiS chipsets to have their real PCI
716# IDs obscured, we have to qualify these with a custom detection
717# routine before we add them to the @pci_adapters list.
718#
719use vars qw(@pci_adapters_sis5595 @pci_adapters_sis645 @pci_adapters_sis96x);
720@pci_adapters_sis5595 = (
721     {
722       vendid => 0x1039,
723       devid  => 0x0008,
724       func => 0,
725       procid => "Silicon Integrated Systems SIS5595",
726       driver => "i2c-sis5595",
727       match => sub {  $_[0] =~ /^SMBus SIS5595 adapter at [0-9,a-f]{4}/ },
728     } ,
729);
730
731@pci_adapters_sis645 = (
732     {
733       vendid => 0x1039,
734       devid  => 0x0008,
735       func => 0,
736       procid => "Silicon Integrated Systems SIS5595",
737       driver => "i2c-sis645",
738       match => sub {  $_[0] =~ /^SiS645 SMBus adapter at [0-9,a-f]{4}/ },
739     } ,
740     {
741       vendid => 0x1039,
742       devid  => 0x0016,
743       func => 1,
744       procid => "Silicon Integrated Systems SMBus Controller",
745       driver => "i2c-sis645",
746       match => sub { $_[0] =~ /^SiS645 SMBus adapter at 0x[0-9,a-f]{4}/ },
747     } ,
748     {
749       vendid => 0x1039,
750       devid  => 0x0018,
751       func => 0,
752       procid => "Silicon Integrated Systems 85C503/5513 (LPC Bridge)",
753       driver => "i2c-sis645",
754       match => sub { $_[0] =~ /^SiS645 SMBus adapter at 0x[0-9,a-f]{4}/ },
755     } ,
756);
757
758@pci_adapters_sis96x = (
759     {
760       vendid => 0x1039,
761       devid  => 0x0016,
762       func => 1,
763       procid => "Silicon Integrated Systems SMBus Controller",
764       driver => "i2c-sis96x",
765       match => sub { $_[0] =~ /^SiS96x SMBus adapter at 0x[0-9,a-f]{4}/ },
766     } ,
767);
768
769use subs qw(mtp008_detect lm78_detect lm78_isa_detect lm78_alias_detect
770            lm75_detect lm80_detect w83781d_detect w83781d_alias_detect
771            adm1025_detect w83781d_isa_detect gl518sm_detect gl520sm_detect
772            adm9240_detect adm1021_detect sis5595_isa_detect eeprom_detect
773            via686a_isa_detect adm1022_detect ltc1710_detect gl525sm_detect
774            lm87_detect ite_detect ite_isa_detect ite_alias_detect
775            ddcmonitor_detect ds1621_detect adm1024_detect fscpos_detect
776            fscscy_detect arp_detect ipmi_kcs_detect
777            ipmi_smic_detect via8231_isa_detect lm85_detect smartbatt_detect
778            adm1026_detect w83l785ts_detect lm83_detect lm90_detect
779            saa1064_detect w83l784r_detect mozart_detect max6650_detect
780            fscher_detect adm1029_detect adm1031_detect max6900_detect
781            m5879_detect pca9540_detect smartbatt_mgr_detect
782            smartbatt_chgr_detect adt7467_detect lm92_detect);
783
784# This is a list of all recognized chips.
785# Each entry must have the following fields:
786#  name: The full chip name
787#  driver: The driver name (without .o extension). Put in exactly
788#      "to-be-written" if it is not yet available.
789#  i2c_addrs (optional): For I2C chips, the range of valid I2C addresses to
790#      probe. Recommend avoiding 0x69 because of clock chips.
791#  i2c_driver_addrs (optional): For I2C chips, the range of valid I2C
792#      addresses probed by the kernel driver. Strictly optional.
793#  i2c_detect (optional): For I2C chips, the function to call to detect
794#      this chip. The function should take two parameters: an open file
795#      descriptor to access the bus, and the I2C address to probe.
796#  isa_addrs (optional): For ISA chips, the range of valid port addresses to
797#      probe.
798#  isa_driver_addrs (optional): For ISA chips, the range of valid ISA
799#      addresses probed by the kernel driver. Strictly optional.
800#  isa_detect (optional): For ISA chips, the function to call to detect
801#      this chip. The function should take one parameter: the ISA address
802#      to probe.
803#  alias_detect (optional): For chips which can be both on the ISA and the
804#      I2C bus, a function which detectes whether two entries are the same.
805#      The function should take three parameters: The ISA address, the
806#      I2C bus number, and the I2C address.
807@chip_ids = (
808     {
809       name => "Myson MTP008",
810       driver => "mtp008",
811       i2c_addrs => [0x2c..0x2e], 
812       i2c_detect => sub { mtp008_detect @_},
813     } ,
814     {
815       name => "National Semiconductor LM78",
816       driver => "lm78",
817       i2c_addrs => [0x20..0x2f], 
818       i2c_detect => sub { lm78_detect 0, @_},
819       isa_addrs => [0x290],
820       isa_detect => sub { lm78_isa_detect 0, @_ },
821       alias_detect => sub { lm78_alias_detect 0, @_ },
822     } ,
823     {
824       name => "National Semiconductor LM78-J",
825       driver => "lm78",
826       i2c_addrs => [0x20..0x2f], 
827       i2c_detect => sub { lm78_detect 1, @_ },
828       isa_addrs => [0x290],
829       isa_detect => sub { lm78_isa_detect 1, @_ },
830       alias_detect => sub { lm78_alias_detect 1, @_ },
831     } ,
832     {
833       name => "National Semiconductor LM79",
834       driver => "lm78",
835       i2c_addrs => [0x20..0x2f], 
836       i2c_detect => sub { lm78_detect 2, @_ },
837       isa_addrs => [0x290],
838       isa_detect => sub { lm78_isa_detect 2, @_ },
839       alias_detect => sub { lm78_alias_detect 2, @_ },
840     } ,
841     {
842       name => "National Semiconductor LM75",
843       driver => "lm75",
844       i2c_addrs => [0x48..0x4f],
845       i2c_detect => sub { lm75_detect @_},
846     } ,
847     {
848       name => "National Semiconductor LM80",
849       driver => "lm80",
850       i2c_addrs => [0x28..0x2f],
851       i2c_detect => sub { lm80_detect @_} ,
852     },
853     {
854       name => "National Semiconductor LM85",
855       driver => "lm85",
856       i2c_addrs => [0x2c..0x2e],
857       i2c_detect => sub { lm85_detect 0x01, @_},
858     },
859     {
860       name => "Analog Devices ADM1027, ADT7460 or ADT7463",
861       driver => "lm85",
862       i2c_addrs => [0x2c..0x2e],
863       i2c_detect => sub { lm85_detect 0x41, @_},
864     },
865     {
866       name => "SMSC EMC6D100 or EMC6D101",
867       driver => "lm85",
868       i2c_addrs => [0x2c..0x2e],
869       i2c_detect => sub { lm85_detect 0x5c, @_},
870     },
871     {
872       name => "Analog Devices ADT7467",
873       driver => "to-be-written",
874       i2c_addrs => [0x2e],
875       i2c_detect => sub { adt7467_detect 0, @_},
876     },
877     {
878       name => "National Semiconductor LM87",
879       driver => "lm87",
880       i2c_addrs => [0x2c..0x2e],
881       i2c_detect => sub { lm87_detect @_} ,
882     },
883     {
884       name => "Winbond W83781D",
885       driver => "w83781d",
886       i2c_detect => sub { w83781d_detect 0, @_},
887       i2c_addrs => [0x20..0x2f], 
888       isa_addrs => [0x290],
889       isa_detect => sub { w83781d_isa_detect 0, @_ },
890       alias_detect => sub { w83781d_alias_detect 0, @_ },
891     } ,
892     {
893       name => "Winbond W83782D",
894       driver => "w83781d",
895       i2c_addrs => [0x20..0x2f], 
896       i2c_detect => sub { w83781d_detect 1, @_},
897       isa_addrs => [0x290],
898       isa_detect => sub { w83781d_isa_detect 1, @_ },
899       alias_detect => sub { w83781d_alias_detect 1, @_ },
900     } ,
901     {
902       name => "Winbond W83783S",
903       driver => "w83781d",
904       i2c_addrs => [0x2d],
905       i2c_detect => sub { w83781d_detect 2, @_},
906     } ,
907     {
908       name => "Winbond W83791D",
909       driver => "w83781d",
910       i2c_addrs => [0x2c..0x2f],
911       i2c_detect => sub { w83781d_detect 7, @_},
912     } ,
913     {
914       name => "Winbond W83627HF",
915       driver => "w83781d",
916       i2c_addrs => [0x20..0x2f], 
917       i2c_detect => sub { w83781d_detect 3, @_},
918       isa_addrs => [0x290],
919       isa_detect => sub { w83781d_isa_detect 3, @_ },
920       alias_detect => sub { w83781d_alias_detect 3, @_ },
921     } ,
922     {
923       name => "Asus AS99127F (rev.1)",
924       driver => "w83781d",
925       i2c_addrs => [0x28..0x2f],
926       i2c_detect => sub { w83781d_detect 4, @_},
927     } ,
928     {
929       name => "Asus AS99127F (rev.2)",
930       driver => "w83781d",
931       i2c_addrs => [0x28..0x2f],
932       i2c_detect => sub { w83781d_detect 5, @_},
933     } ,
934     {
935       name => "Asus ASB100 Bach",
936       driver => "asb100",
937       i2c_addrs => [0x28..0x2f],
938       i2c_detect => sub { w83781d_detect 6, @_},
939     } ,
940     {
941       name => "Asus ASM58 Mozart-2",
942       driver => "to-be-written",
943       i2c_addrs => [0x77],
944       i2c_detect => sub { mozart_detect 0, @_},
945     } ,
946     {
947       name => "Asus AS2K129R Mozart-2",
948       driver => "to-be-written",
949       i2c_addrs => [0x77],
950       i2c_detect => sub { mozart_detect 1, @_},
951     } ,
952     {
953       name => "Asus Mozart-2",
954       driver => "to-be-written",
955       i2c_addrs => [0x77],
956       i2c_detect => sub { mozart_detect 2, @_},
957     } ,
958     {
959       name => "Winbond W83L784R/AR",
960       driver => "to-be-written",
961       i2c_addrs => [0x2d],
962       i2c_detect => sub { w83l784r_detect 0, @_},
963     } ,
964     {
965       name => "Winbond W83L785R",
966       driver => "to-be-written",
967       i2c_addrs => [0x2d],
968       i2c_detect => sub { w83l784r_detect 1, @_},
969     } ,
970     {
971       name => "Winbond W83L785TS-S",
972       driver => "w83l785ts",
973       i2c_addrs => [0x2e], 
974       i2c_detect => sub { w83l785ts_detect 0, @_},
975     } ,
976     {
977       name => "Winbond W83697HF",
978       driver => "w83781d",
979       isa_addrs => [0x290],
980       isa_detect => sub { w83781d_isa_detect 5, @_ },
981     } ,
982     {
983       name => "Genesys Logic GL518SM Revision 0x00",
984       driver => "gl518sm",
985       i2c_addrs => [0x2c, 0x2d],
986       i2c_detect => sub { gl518sm_detect 0, @_} ,
987     },
988     {
989       name => "Genesys Logic GL518SM Revision 0x80",
990       driver => "gl518sm",
991       i2c_addrs => [0x2c, 0x2d],
992       i2c_detect => sub { gl518sm_detect 1, @_} ,
993     },
994     {
995       name => "Genesys Logic GL520SM",
996       driver => "gl520sm",
997       i2c_addrs => [0x2c, 0x2d],
998       i2c_detect => sub { gl520sm_detect @_} ,
999     },
1000     {
1001       name => "Genesys Logic GL525SM",
1002       driver => "Unwritten (GL525SM)",
1003       i2c_addrs => [0x2d],
1004       i2c_detect => sub { gl525sm_detect @_} ,
1005     },
1006     {
1007       name => "Analog Devices ADM9240",
1008       driver => "adm9240",
1009       i2c_addrs => [0x2c..0x2f],
1010       i2c_detect => sub { adm9240_detect 0, @_ }
1011     },
1012     {
1013       name => "Dallas Semiconductor DS1621",
1014       driver => "ds1621",
1015       i2c_addrs => [0x48..0x4f],
1016       i2c_detect => sub { ds1621_detect @_},
1017     } ,
1018     {
1019       name => "Dallas Semiconductor DS1780",
1020       driver => "adm9240",
1021       i2c_addrs => [0x2c..0x2f],
1022       i2c_detect => sub { adm9240_detect 1, @_ }
1023     },
1024     {
1025       name => "National Semiconductor LM81",
1026       driver => "adm9240",
1027       i2c_addrs => [0x2c..0x2f],
1028       i2c_detect => sub { adm9240_detect 2, @_ }
1029     },
1030     {
1031       name => "Analog Devices ADM1026",
1032       driver => "adm1026",
1033       i2c_addrs => [0x2c,0x2d,0x2e],
1034       i2c_detect => sub { adm1026_detect 0, @_ }
1035     },
1036     {
1037       name => "Analog Devices ADM1025",
1038       driver => "adm1025",
1039       i2c_addrs => [0x2c..0x2e],
1040       i2c_detect => sub { adm1025_detect 0, @_ }
1041     },
1042     {
1043       name => "Philips NE1619",
1044       driver => "adm1025",
1045       i2c_addrs => [0x2c..0x2d],
1046       i2c_detect => sub { adm1025_detect 1, @_ }
1047     },
1048     {
1049       name => "Analog Devices ADM1024",
1050       driver => "adm1024",
1051       i2c_addrs => [0x2c..0x2e],
1052       i2c_detect => sub { adm1024_detect 0, @_ }
1053     },
1054     {
1055       name => "Analog Devices ADM1021",
1056       driver => "adm1021",
1057       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
1058       i2c_detect => sub { adm1021_detect 0, @_ },
1059     },
1060     {
1061       name => "Analog Devices ADM1021A/ADM1023",
1062       driver => "adm1021",
1063       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
1064       i2c_detect => sub { adm1021_detect 1, @_ },
1065     },
1066     {
1067       name => "Maxim MAX1617",
1068       driver => "adm1021",
1069       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
1070       i2c_detect => sub { adm1021_detect 2, @_ },
1071     },
1072     {
1073       name => "Maxim MAX1617A",
1074       driver => "adm1021",
1075       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
1076       i2c_detect => sub { adm1021_detect 3, @_ },
1077     },
1078     {
1079       name => "Maxim MAX6650/MAX6651",
1080       driver => "max6650",
1081       i2c_addrs => [0x1b,0x1f,0x48,0x4b],
1082       i2c_detect => sub { max6650_detect 0, @_ },
1083     },
1084     {
1085       name => "TI THMC10",
1086       driver => "adm1021",
1087       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
1088       i2c_detect => sub { adm1021_detect 4, @_ },
1089     },
1090     {
1091       name => "National Semiconductor LM84",
1092       driver => "adm1021",
1093       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
1094       i2c_detect => sub { adm1021_detect 5, @_ },
1095     },
1096     {
1097       name => "Genesys Logic GL523SM",
1098       driver => "adm1021",
1099       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
1100       i2c_detect => sub { adm1021_detect 6, @_ },
1101     },
1102     {
1103       name => "Onsemi MC1066",
1104       driver => "adm1021",
1105       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
1106       i2c_detect => sub { adm1021_detect 7, @_ },
1107     },
1108     {
1109       name => "National Semiconductor LM82",
1110       driver => "to-be-written",
1111       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
1112       i2c_detect => sub { lm83_detect 1, @_ },
1113     },
1114     {
1115       name => "National Semiconductor LM83",
1116       driver => "lm83",
1117       i2c_addrs => [0x18..0x1a,0x29..0x2b,0x4c..0x4e],
1118       i2c_detect => sub { lm83_detect 0, @_ },
1119     },
1120     {
1121       name => "National Semiconductor LM90",
1122       driver => "lm90",
1123       i2c_addrs => [0x4c],
1124       i2c_detect => sub { lm90_detect 0, @_ },
1125     },
1126     {
1127       name => "National Semiconductor LM89",
1128       driver => "to-be-written",
1129       i2c_addrs => [0x4c],
1130       i2c_detect => sub { lm90_detect 1, @_ },
1131     },
1132     {
1133       name => "National Semiconductor LM86",
1134       driver => "to-be-written",
1135       i2c_addrs => [0x4c],
1136       i2c_detect => sub { lm90_detect 2, @_ },
1137     },
1138     {
1139       name => "Analog Devices ADM1032",
1140       driver => "lm90",
1141       i2c_addrs => [0x4c],
1142       i2c_detect => sub { lm90_detect 3, @_ },
1143     },
1144     {
1145       name => "Maxim MAX6657/MAX6658",
1146       driver => "to-be-written",
1147       i2c_addrs => [0x4c],
1148       i2c_detect => sub { lm90_detect 4, @_ },
1149     },
1150     {
1151       name => "National Semiconductor LM92",
1152       driver => "lm92",
1153       i2c_addrs => [0x48..0x4b],
1154       i2c_detect => sub { lm92_detect 0, @_ },
1155     },
1156     {
1157       name => "National Semiconductor LM76",
1158       driver => "lm92",
1159       i2c_addrs => [0x48..0x4b],
1160       i2c_detect => sub { lm92_detect 1, @_ },
1161     },
1162     {
1163       name => "Maxim MAX6633/MAX6634/MAX6635",
1164       driver => "lm92",
1165       i2c_addrs => [0x40..0x4f],
1166       i2c_detect => sub { lm92_detect 2, @_ },
1167     },
1168     {
1169       name => "Analog Devices ADT7461",
1170       driver => "to-be-written",
1171       i2c_addrs => [0x4c],
1172       i2c_detect => sub { lm90_detect 5, @_ },
1173     },
1174     {
1175       name => "Analog Devices ADM1029",
1176       driver => "to-be-written",
1177       i2c_addrs => [0x28..0x2f],
1178       i2c_detect => sub { adm1029_detect 0, @_ },
1179     },
1180     {
1181       name => "Analog Devices ADM1030",
1182       driver => "to-be-written",
1183       i2c_addrs => [0x2c..0x2e],
1184       i2c_detect => sub { adm1031_detect 0, @_ },
1185     },
1186     {
1187       name => "Analog Devices ADM1031",
1188       driver => "to-be-written",
1189       i2c_addrs => [0x2c..0x2e],
1190       i2c_detect => sub { adm1031_detect 1, @_ },
1191     },
1192     {
1193       name => "Analog Devices ADM1022",
1194       driver => "thmc50",
1195       i2c_addrs => [0x2c..0x2e],
1196       i2c_detect => sub { adm1022_detect 0, @_ },
1197     },
1198     {
1199       name => "Texas Instruments THMC50",
1200       driver => "thmc50",
1201       i2c_addrs => [0x2c..0x2e],
1202       i2c_detect => sub { adm1022_detect 1, @_ },
1203     },
1204     {
1205       name => "Analog Devices ADM1028",
1206       driver => "thmc50",
1207       i2c_addrs => [0x2e],
1208       i2c_detect => sub { adm1022_detect 2, @_ },
1209     },
1210     {
1211       name => "Silicon Integrated Systems SIS5595",
1212       driver => "sis5595",
1213       isa_addrs => [ 0 ],
1214       isa_detect => sub { sis5595_isa_detect @_ },
1215     },
1216     {
1217       name => "VIA Technologies VT82C686 Integrated Sensors",
1218       driver => "via686a",
1219       isa_addrs => [ 0 ],
1220       isa_detect => sub { via686a_isa_detect @_ },
1221     },
1222     {
1223       name => "VIA Technologies VT8231 Integrated Sensors",
1224       driver => "vt8231",
1225       isa_addrs => [ 0 ],
1226       isa_detect => sub { via8231_isa_detect @_ },
1227     },
1228     {
1229       name => "ITE IT8705F / IT8712F / SiS 950",
1230       driver => "it87",
1231       i2c_addrs => [0x20..0x2f],
1232       i2c_detect => sub { ite_detect 0, @_ },
1233       isa_addrs => [0x290],
1234       isa_detect => sub { ite_isa_detect 0, @_ },
1235     } ,
1236     {
1237       name => "SPD EEPROM",
1238       driver => "eeprom",
1239       i2c_addrs => [0x50..0x57],
1240       i2c_detect => sub { eeprom_detect 0, @_ },
1241     },
1242     {
1243       name => "Sony Vaio EEPROM",
1244       driver => "eeprom",
1245       i2c_addrs => [0x57],
1246       i2c_detect => sub { eeprom_detect 1, @_ },
1247     },
1248     {
1249       name => "LTC1710",
1250       driver => "ltc1710",
1251       i2c_addrs => [0x58..0x5a],
1252       i2c_detect => sub { ltc1710_detect @_ },
1253     },
1254     {
1255       name => "DDC monitor",
1256       driver => "ddcmon",
1257       i2c_addrs => [0x50],
1258       i2c_detect => sub { ddcmonitor_detect @_ },
1259     },
1260     {
1261       name => "FSC Poseidon",
1262       driver => "fscpos",
1263       i2c_addrs => [0x73],
1264       i2c_detect => sub { fscpos_detect @_ },
1265     },
1266     {
1267       name => "FSC Scylla",
1268       driver => "fscscy",
1269       i2c_addrs => [0x73],
1270       i2c_detect => sub { fscscy_detect @_ },
1271     },
1272     {
1273       name => "FSC Hermes",
1274       driver => "fscher",
1275       i2c_addrs => [0x73],
1276       i2c_detect => sub { fscher_detect @_ },
1277     },
1278     {
1279       name => "ALi M5879",
1280       driver => "to-be-written",
1281       i2c_addrs => [0x2c..0x2d],
1282       i2c_detect => sub { m5879_detect @_},
1283     } ,
1284     {
1285       name => "Philips Semiconductors SAA1064",
1286       driver => "saa1064",
1287       i2c_addrs => [0x38..0x3b],
1288       i2c_detect => sub { saa1064_detect @_ },
1289     },
1290     {
1291       name => "Philips Semiconductors PCA9540",
1292       driver => "pca9540",
1293       i2c_addrs => [0x70],
1294       i2c_detect => sub { pca9540_detect @_ },
1295     },
1296     {
1297       name => "Maxim MAX6900",
1298       driver => "to-be-written",
1299       i2c_addrs => [0x50],
1300       i2c_detect => sub { max6900_detect @_ },
1301     },
1302     {
1303       name => "SMBus 2.0 ARP-Capable Device",
1304       driver => "smbus-arp",
1305       i2c_addrs => [0x61],
1306       i2c_detect => sub { arp_detect @_},
1307     },
1308     {
1309       name => "IPMI BMC KCS",
1310       driver => "bmcsensors",
1311       isa_addrs => [ 0x0ca0 ],
1312       isa_detect => sub { ipmi_kcs_detect @_ },
1313     },
1314     {
1315       name => "IPMI BMC SMIC",
1316       driver => "bmcsensors",
1317       isa_addrs => [ 0x0ca8 ],
1318       isa_detect => sub { ipmi_smic_detect @_ },
1319     },
1320     {
1321       name => "Smart Battery Charger",
1322       driver => "to-be-written",
1323       i2c_addrs => [0x09],
1324       i2c_detect => sub { smartbatt_chgr_detect @_},
1325     },
1326     {
1327       name => "Smart Battery Manager/Selector",
1328       driver => "to-be-written",
1329       i2c_addrs => [0x0a],
1330       i2c_detect => sub { smartbatt_mgr_detect @_},
1331     },
1332     {
1333       name => "Smart Battery",
1334       driver => "smartbatt",
1335       i2c_addrs => [0x0b],
1336       i2c_detect => sub { smartbatt_detect @_},
1337     },
1338);
1339
1340# This is a list of all recognized superio chips.
1341# Each entry must have the following fields:
1342#  name: The full chip name
1343#  driver: The driver name (without .o extension). Put in
1344#      "to-be-written" if it is not yet available.
1345#      Put in "not-a-sensor" if the chip doesn't have hardware monitoring
1346#      capabilities (listing such chips here removes the need of manual
1347#      lookup when people report them).
1348#  enter: The password sequence to write to the address register
1349#  devid: The device ID(s) we have to match (base device)
1350#  logdev: The logical device containing the sensors
1351#  exit (optional): Sequence to write to the address register to exit config
1352#      mode. If not provided, a default reset operation is performed.
1353#  alias_detect (optional): For chips which can be both on the ISA and the
1354#      I2C bus, a function which detectes whether two entries are the same.
1355#      The function should take three parameters: The ISA address, the
1356#      I2C bus number, and the I2C address.
1357@superio_ids = (
1358  {
1359    enter => [0x87, 0x01, 0x55, 0x55],
1360    chips =>
1361    [
1362      {
1363        name => "ITE 8702F Super IO Sensors",
1364        driver => "to-be-written",
1365        devid => 0x8702,
1366        logdev => 0x04,
1367      },
1368      {
1369        name => "ITE 8705F Super IO Sensors",
1370        driver => "it87",
1371        devid => 0x8705,
1372        logdev => 0x04,
1373      },
1374      {
1375        name => "ITE 8712F Super IO Sensors",
1376        driver => "it87",
1377        devid => 0x8712,
1378        logdev => 0x04,
1379      },
1380    ],
1381  },
1382  {
1383    enter => [],
1384    chips =>
1385    [
1386      {
1387        name => "Nat. Semi. PC87351 Super IO Fan Sensors",
1388        driver => "to-be-written",
1389        devid => 0xe2,
1390        logdev => 0x08,
1391      },
1392      {
1393        name => "Nat. Semi. PC87360 Super IO Fan Sensors",
1394        driver => "pc87360",
1395        devid => 0xe1,
1396        logdev => 0x09,
1397      },
1398      {
1399        name => "Nat. Semi. PC87363 Super IO Fan Sensors",
1400        driver => "pc87360",
1401        devid => 0xe8,
1402        logdev => 0x09,
1403      },
1404      {
1405        name => "Nat. Semi. PC87364 Super IO Fan Sensors",
1406        driver => "pc87360",
1407        devid => 0xe4,
1408        logdev => 0x09,
1409      },
1410      {
1411        name => "Nat. Semi. PC87365 Super IO Fan Sensors",
1412        driver => "pc87360",
1413        devid => 0xe5,
1414        logdev => 0x09,
1415      },
1416      {
1417        name => "Nat. Semi. PC87365 Super IO Voltage Sensors",
1418        driver => "pc87360",
1419        devid => 0xe5,
1420        logdev => 0x0d,
1421      },
1422      {
1423        name => "Nat. Semi. PC87365 Super IO Thermal Sensors",
1424        driver => "pc87360",
1425        devid => 0xe5,
1426        logdev => 0x0e,
1427      },
1428      {
1429        name => "Nat. Semi. PC87366 Super IO Fan Sensors",
1430        driver => "pc87360",
1431        devid => 0xe9,
1432        logdev => 0x09,
1433      },
1434      {
1435        name => "Nat. Semi. PC87366 Super IO Voltage Sensors",
1436        driver => "pc87360",
1437        devid => 0xe9,
1438        logdev => 0x0d,
1439      },
1440      {
1441        name => "Nat. Semi. PC87366 Super IO Thermal Sensors",
1442        driver => "pc87360",
1443        devid => 0xe9,
1444        logdev => 0x0e,
1445      },
1446      {
1447        name => "Nat. Semi. PC87372 Super IO Fan Sensors",
1448        driver => "to-be-written",
1449        devid => 0xf0,
1450        logdev => 0x09,
1451      },
1452      {
1453        name => "Nat. Semi. PC8741x Super IO",
1454        driver => "not-a-sensor",
1455        devid => 0xee,
1456      },
1457    ],
1458  },
1459  {
1460    enter => [0x55],
1461    exit => [0xaa],
1462    chips =>
1463    [
1464      {
1465        name => "SMSC 47B27x Super IO Fan Sensors",
1466        driver => "smsc47m1",
1467        devid => 0x51,
1468        logdev => 0x0a,
1469      },
1470      {
1471        name => "SMSC 47M10x/13x Super IO Fan Sensors",
1472        driver => "smsc47m1",
1473        devid => 0x59,
1474        logdev => 0x0a,
1475      },
1476      {
1477        name => "SMSC 47M14x Super IO Fan Sensors",
1478        driver => "smsc47m1",
1479        devid => 0x5f,
1480        logdev => 0x0a,
1481      },
1482      {
1483        name => "SMSC 47M15x/192 Super IO Fan Sensors",
1484        driver => "to-be-written",
1485        devid => 0x60,
1486        logdev => 0x0a,
1487      },
1488      {
1489        name => "SMSC 47S42x Super IO Fan Sensors",
1490        driver => "to-be-written",
1491        devid => 0x57,
1492        logdev => 0x0a,
1493      },
1494      {
1495        name => "SMSC 47S45x Super IO Fan Sensors",
1496        driver => "to-be-written",
1497        devid => 0x62,
1498        logdev => 0x0a,
1499      },
1500      {
1501        name => "SMSC 47M172 Super IO",
1502        driver => "not-a-sensor",
1503        devid => 0x14,
1504      },
1505    ],
1506  },
1507  {
1508    enter => [0x87, 0x87],
1509    exit => [0xaa],
1510    chips =>
1511    [
1512      {
1513        name => "VT1211 Super IO Sensors",
1514        driver => "vt1211",
1515        devid => 0x3c,
1516        logdev => 0x0b,
1517      },
1518      {
1519        name => "Winbond W83627HF Super IO Sensors",
1520        driver => "w83627hf",
1521        devid => 0x52,
1522        logdev => 0x0b,
1523      },
1524      {
1525        name => "Winbond W83627THF Super IO Sensors",
1526        driver => "w83627hf",
1527        devid => 0x82,
1528        logdev => 0x0b,
1529      },
1530      {
1531        name => "Winbond W83637HF Super IO Sensors",
1532        driver => "w83627hf",
1533        devid => 0x70,
1534        logdev => 0x0b,
1535      },
1536      {
1537        name => "Winbond W83697HF Super IO Sensors",
1538        driver => "w83627hf",
1539        devid => 0x60,
1540        logdev => 0x0b,
1541      },
1542      {
1543        name => "Winbond W83697SF/UF Super IO PWM",
1544        driver => "to-be-written",
1545        devid => 0x68,
1546        logdev => 0x0b,
1547      },
1548      {
1549        name => "Winbond W83L517D Super IO",
1550        driver => "not-a-sensor",
1551        devid => 0x61,
1552      },
1553    ],
1554  },
1555);
1556
1557#######################
1558# AUXILIARY FUNCTIONS #
1559#######################
1560
1561sub swap_bytes
1562{
1563  return (($_[0] & 0xff00) >> 8) + (($_[0] & 0x00ff) << 8)
1564}
1565
1566# $_[0] is the sought value
1567# @_[1..] is the list to seek in
1568# Returns: 0 on failure, 1 if found.
1569sub contains
1570{
1571  my $sought = shift;
1572  foreach (@_) {
1573    return 1 if $sought eq $_;
1574  }
1575  return 0;
1576}
1577
1578sub parse_not_to_scan
1579{
1580  my ($min,$max,$to_parse) = @_;
1581  my @ranges = split /\s*,\s*/, $to_parse;
1582  my @res = ();
1583  my $range;
1584  foreach $range (@ranges) {
1585    my ($start,$end) = split /\s*-s*/, $range;
1586    $start = oct $start if $start =~ /^0/;
1587    if (defined $end) {
1588      $end = oct $end if $end =~ /^0/;
1589      $start = $min if $start < $min;
1590      $end = $max if $end > $max;
1591      push @res, ($start+0..$end+0);
1592    } else {
1593      push @res, $start+0 if $start >= $min and $start <= $max;
1594    }
1595  }
1596  return sort { $a <=> $b } @res;
1597}
1598
1599# @_[0]: Reference to list 1
1600# @_[1]: Reference to list 2
1601# Result: 0 if they have no elements in common, 1 if they have
1602# Elements must be numeric.
1603sub any_list_match
1604{
1605  my ($list1,$list2) = @_;
1606  my ($el1,$el2);
1607  foreach $el1 (@$list1) {
1608    foreach $el2 (@$list2) {
1609      return 1 if $el1 == $el2;
1610    }
1611  }
1612  return 0;
1613}
1614
1615###################
1616# I/O port access #
1617###################
1618
1619sub initialize_ioports
1620{
1621  sysopen (IOPORTS, "/dev/port", O_RDWR)
1622    or die "/dev/port: $!\n";
1623  binmode IOPORTS;
1624}
1625
1626sub close_ioports
1627{
1628  close (IOPORTS)
1629    or print "Warning: $!\n";
1630}
1631
1632# $_[0]: port to read
1633# Returns: -1 on failure, read value on success.
1634sub inb
1635{
1636  my ($res,$nrchars);
1637  sysseek IOPORTS, $_[0], 0 or return -1;
1638  $nrchars = sysread IOPORTS, $res, 1;
1639  return -1 if not defined $nrchars or $nrchars != 1;
1640  $res = unpack "C",$res ;
1641  return $res;
1642}
1643
1644# $_[0]: port to write
1645# $_[1]: value to write
1646# Returns: -1 on failure, 0 on success.
1647sub outb
1648{
1649  if ($_[1] > 0xff)
1650  {
1651    my ($package, $filename, $line, $sub) = caller(1);
1652    print "\n*** Called outb with value=$_[1] from line $line\n",
1653          "*** (in $sub). PLEASE REPORT!\n",
1654          "*** Terminating.\n";
1655    exit(-1);
1656  }
1657  my $towrite = pack "C", $_[1];
1658  sysseek IOPORTS, $_[0], 0 or return -1;
1659  my $nrchars = syswrite IOPORTS, $towrite, 1;
1660  return -1 if not defined $nrchars or $nrchars != 1;
1661  return 0;
1662}
1663
1664# $_[0]: Address register
1665# $_[1]: Data register
1666# $_[2]: Register to read
1667# Returns: read value
1668sub isa_read_byte
1669{
1670  outb $_[0],$_[2];
1671  return inb $_[1];
1672}
1673
1674# $_[0]: Address register
1675# $_[1]: Data register
1676# $_[2]: Register to write
1677# $_[3}: Value to write
1678# Returns: nothing
1679sub isa_write_byte
1680{
1681  outb $_[0],$_[2];
1682  outb $_[1],$_[3];
1683}
1684
1685#################
1686# AUTODETECTION #
1687#################
1688
1689use vars qw($modules_conf $dev_i2c);
1690
1691sub initialize_conf
1692{
1693  my $use_devfs = 0;
1694  open INPUTFILE, "/proc/mounts" or die "Can't access /proc/mounts!";
1695  while (<INPUTFILE>) {
1696    if (m@^none /dev devfs @) {
1697      $use_devfs = 1;
1698      $dev_i2c = '/dev/i2c/';
1699      last;
1700    }
1701  }
1702  close INPUTFILE;
1703
1704  if (-f '/etc/modules.conf') {
1705    $modules_conf = '/etc/modules.conf';
1706  } elsif (-f '/etc/conf.modules') {
1707    $modules_conf = '/etc/conf.modules';
1708  } else { # default
1709    $modules_conf = '/etc/modules.conf';
1710  }
1711
1712  if (!$use_devfs) {
1713    if (-c '/dev/i2c-0') {
1714      $dev_i2c = '/dev/i2c-';
1715    } else { # default
1716      print "No i2c device files found. Use prog/mkdev/mkdev.sh to create them.\n";
1717      exit -1;
1718    }
1719  }
1720}
1721
1722# [0] -> VERSION
1723# [1] -> PATCHLEVEL
1724# [2] -> SUBLEVEL
1725# [3] -> EXTRAVERSION
1726#
1727use vars qw(@kernel_version);
1728
1729sub initialize_kernel_version
1730{
1731  `uname -r` =~ /(\d+)\.(\d+)\.(\d+)(.*)/;
1732  @kernel_version = ($1, $2, $3, $4);
1733}
1734
1735sub kernel_version_at_least
1736{
1737  my ($vers, $plvl, $slvl) = @_;
1738  return 1 if ($kernel_version[0]  > $vers ||
1739                ($kernel_version[0] == $vers && 
1740                  ($kernel_version[1]  > $plvl || 
1741                    ($kernel_version[1] == $plvl && 
1742                      ($kernel_version[2] >= $slvl)))));
1743  return 0;
1744}
1745
1746###########
1747# MODULES #
1748###########
1749
1750use vars qw(%modules_list);
1751
1752sub initialize_modules_list
1753{
1754  open INPUTFILE, "/proc/modules" or die "Can't access /proc/modules!";
1755  while (<INPUTFILE>) {
1756    tr/_/-/;
1757    $modules_list{$1} = 1 if m/^(\S*)/;
1758  }
1759  close INPUTFILE;
1760}
1761
1762##############
1763# PCI ACCESS #
1764##############
1765
1766use vars qw(%pci_list);
1767
1768# This function returns a hash of hashes. Each hash has some PCI information
1769# (more than we will ever need, probably). The most important
1770# fields are 'bus', 'slot', 'func' (they uniquely identify a PCI device in
1771# a computer) and 'vendid','devid' (they uniquely identify a type of device).
1772sub read_proc_dev_pci
1773{
1774  my ($dfn,$vend,%pci_list);
1775  open INPUTFILE, "/proc/bus/pci/devices" or return;
1776  while (<INPUTFILE>) {
1777    my $record = {};
1778    ($dfn,$vend,$record->{irq},$record->{base_addr0},$record->{base_addr1},
1779          $record->{base_addr2},$record->{base_addr3},$record->{base_addr4},
1780          $record->{base_addr5},$record->{rom_base_addr}) = 
1781          map { oct "0x$_" } (split) [0..9];
1782    $record->{bus} = $dfn >> 8;
1783    $record->{slot} = ($dfn & 0xf8) >> 3;
1784    $record->{func} = $dfn & 0x07;
1785    $record->{vendid} = $vend >> 16;
1786    $record->{devid} = $vend & 0xffff;
1787   
1788    $pci_list{ sprintf("%04x:%04x",$record->{vendid},$record->{devid}) } =
1789        $record;
1790  }
1791  close INPUTFILE or return;
1792  return %pci_list;
1793}
1794
1795sub initialize_proc_pci
1796{
1797  %pci_list = read_proc_dev_pci;
1798  die "Can't access /proc/bus/pci/devices!" if not defined %pci_list;
1799}
1800
1801#####################
1802# ADAPTER DETECTION #
1803#####################
1804
1805sub all_available_adapters
1806{
1807  my @res = ();
1808  foreach my $adapter (@pci_adapters) {
1809    push @res, $adapter->{driver}
1810      if exists $modules_list{$adapter->{driver}};
1811  }
1812  return @res;
1813}
1814
1815sub adapter_pci_detection_sis_96x
1816{
1817  my $driver="";
1818
1819  # first, determine which driver if any...
1820  if (kernel_version_at_least(2,6,0)) {
1821    if (exists $pci_list{"1039:0016"}) {
1822      $driver = "i2c-sis96x";
1823    } elsif (exists $pci_list{"1039:0008"}) {
1824      $driver = "i2c-sis5595";
1825    }
1826  } elsif (kernel_version_at_least(2,4,0)) {
1827    if (exists $pci_list{"1039:0008"}) {
1828      if ((exists $pci_list{"1039:0645"}) ||
1829          (exists $pci_list{"1039:0646"}) ||
1830          (exists $pci_list{"1039:0648"}) ||
1831          (exists $pci_list{"1039:0650"}) ||
1832          (exists $pci_list{"1039:0651"}) ||
1833          (exists $pci_list{"1039:0655"}) ||
1834          (exists $pci_list{"1039:0735"}) ||
1835          (exists $pci_list{"1039:0745"}) ||
1836          (exists $pci_list{"1039:0746"})) {
1837        $driver = "i2c-sis645";
1838      } else {
1839        $driver = "i2c-sis5595";
1840      }
1841    } elsif ((exists $pci_list{"1039:0016"}) ||
1842             (exists $pci_list{"1039:0018"})) {
1843      $driver = "i2c-sis645";
1844    }
1845  }
1846
1847  # then, add the appropriate entries to @pci_adapters
1848  if ($driver eq "i2c-sis5595") {
1849    push @pci_adapters, @pci_adapters_sis5595;
1850  } elsif ($driver eq "i2c-sis645") {
1851    push @pci_adapters, @pci_adapters_sis645;
1852  } elsif ($driver eq "i2c-sis96x") {
1853    push @pci_adapters, @pci_adapters_sis96x;
1854  }
1855}
1856
1857sub adapter_pci_detection
1858{
1859  my ($key,$device,$try,@res);
1860  print "Probing for PCI bus adapters...\n";
1861
1862  # Custom detection routine for some SiS chipsets
1863  adapter_pci_detection_sis_96x();
1864
1865  # Generic detection loop
1866  while ( ($key, $device) = each %pci_list) {
1867    foreach $try (@pci_adapters) {
1868      if ((defined($device->{vendid}) and 
1869           $try->{vendid} == $device->{vendid} and
1870           $try->{devid} == $device->{devid} and
1871           $try->{func} == $device->{func}) or
1872          (! defined($device->{vendid}) and
1873           $device->{desc} =~ /$try->{procid}/ and
1874           $try->{func} == $device->{func})) {
1875        printf "Use driver `%s' for device %02x:%02x.%x: %s\n",
1876               $try->{driver}?$try->{driver}:"<To Be Written>",
1877               $device->{bus},$device->{slot},$device->{func},$try->{procid};
1878        push @res,$try->{driver};
1879      }
1880    }
1881  }
1882  if (! @res) {
1883    print ("Sorry, no PCI bus adapters found.\n");
1884  } else {
1885    printf ("Probe succesfully concluded.\n");
1886  }
1887  return @res;
1888}
1889
1890# $_[0]: Adapter description as found in /proc/bus/i2c
1891# $_[1]: Algorithm description as found in /proc/bus/i2c
1892sub find_adapter_driver
1893{
1894  my $adapter;
1895  for $adapter (@pci_adapters) {
1896    return $adapter->{driver} if &{$adapter->{match}} ($_[0],$_[1]);
1897  }
1898  return "UNKNOWN";
1899}
1900
1901#############################
1902# I2C AND SMBUS /DEV ACCESS #
1903#############################
1904
1905# This should really go into a separate module/package.
1906
1907# To do: support i2c-level access (through sysread/syswrite, probably).
1908# I can't test this at all (PIIX4 does not support this), so I have not
1909# included it.
1910
1911use vars qw($IOCTL_I2C_RETRIES $IOCTL_I2C_TIMEOUT $IOCTL_I2C_UDELAY
1912            $IOCTL_I2C_MDELAY $IOCTL_I2C_SLAVE $IOCTL_I2C_TENBIT
1913            $IOCTL_I2C_SMBUS);
1914
1915# These are copied from <linux/i2c.h> and <linux/smbus.h>
1916
1917# For bit-adapters:
1918$IOCTL_I2C_RETRIES = 0x0701;
1919$IOCTL_I2C_TIMEOUT = 0x0702;
1920$IOCTL_I2C_UDELAY = 0x0705;
1921$IOCTL_I2C_MDELAY = 0x0706;
1922
1923# General ones:
1924$IOCTL_I2C_SLAVE = 0x0703;
1925$IOCTL_I2C_TENBIT = 0x0704;
1926$IOCTL_I2C_SMBUS = 0x0720;
1927
1928
1929
1930use vars qw($SMBUS_READ $SMBUS_WRITE $SMBUS_QUICK $SMBUS_BYTE $SMBUS_BYTE_DATA
1931            $SMBUS_WORD_DATA $SMBUS_PROC_CALL $SMBUS_BLOCK_DATA);
1932
1933# These are copied from <linux/smbus.h>
1934
1935$SMBUS_READ = 1;
1936$SMBUS_WRITE = 0;
1937$SMBUS_QUICK = 0;
1938$SMBUS_BYTE = 1;
1939$SMBUS_BYTE_DATA  = 2;
1940$SMBUS_WORD_DATA  = 3;
1941$SMBUS_PROC_CALL = 4;
1942$SMBUS_BLOCK_DATA = 5;
1943
1944# Select the device to communicate with through its address.
1945# $_[0]: Reference to an opened filehandle
1946# $_[1]: Address to select
1947# Returns: 0 on failure, 1 on success.
1948sub i2c_set_slave_addr
1949{
1950  my ($file,$addr) = @_;
1951  ioctl $file, $IOCTL_I2C_SLAVE, $addr or return 0;
1952  return 1;
1953}
1954
1955# i2c_smbus_access is based upon the corresponding C function (see
1956# <linux/i2c-dev.h>). You should not need to call this directly.
1957# Exact calling conventions are intricate; read i2c-dev.c if you really need
1958# to know.
1959# $_[0]: Reference to an opened filehandle
1960# $_[1]: $SMBUS_READ for reading, $SMBUS_WRITE for writing
1961# $_[2]: Command (usually register number)
1962# $_[3]: Transaction kind ($SMBUS_BYTE, $SMBUS_BYTE_DATA, etc.)
1963# $_[4]: Reference to an array used for input/output of data
1964# Returns: 0 on failure, 1 on success.
1965# Note that we need to get back to Integer boundaries through the 'x2'
1966# in the pack. This is very compiler-dependent; I wish there was some other
1967# way to do this.
1968sub i2c_smbus_access
1969{
1970  my ($file,$read_write,$command,$size,$data) = @_;
1971  my $data_array = pack "C32", @$data;
1972  my $ioctl_data = pack "C2x2Ip", ($read_write,$command,$size,$data_array);
1973  ioctl $file, $IOCTL_I2C_SMBUS, $ioctl_data or return 0;
1974  $_[4] = [ unpack "C32",$data_array ];
1975  return 1;
1976}
1977
1978# $_[0]: Reference to an opened filehandle
1979# $_[1]: Either 0 or 1
1980# Returns: -1 on failure, the 0 on success.
1981sub i2c_smbus_write_quick
1982{
1983  my ($file,$value) = @_;
1984  my $data = [];
1985  i2c_smbus_access $file, $value, 0, $SMBUS_QUICK, $data 
1986         or return -1;
1987  return 0;
1988}
1989
1990# $_[0]: Reference to an opened filehandle
1991# Returns: -1 on failure, the read byte on success.
1992sub i2c_smbus_read_byte
1993{
1994  my ($file) = @_;
1995  my $data = [];
1996  i2c_smbus_access $file, $SMBUS_READ, 0, $SMBUS_BYTE, $data 
1997         or return -1;
1998  return $$data[0];
1999}
2000
2001# $_[0]: Reference to an opened filehandle
2002# $_[1]: Byte to write
2003# Returns: -1 on failure, 0 on success.
2004sub i2c_smbus_write_byte
2005{
2006  my ($file,$command) = @_;
2007  my $data = [$command];
2008  i2c_smbus_access $file, $SMBUS_WRITE, 0, $SMBUS_BYTE, $data 
2009         or return -1;
2010  return 0;
2011}
2012
2013# $_[0]: Reference to an opened filehandle
2014# $_[1]: Command byte (usually register number)
2015# Returns: -1 on failure, the read byte on success.
2016sub i2c_smbus_read_byte_data
2017{
2018  my ($file,$command) = @_;
2019  my $data = [];
2020  i2c_smbus_access $file, $SMBUS_READ, $command, $SMBUS_BYTE_DATA, $data 
2021         or return -1;
2022  return $$data[0];
2023}
2024 
2025# $_[0]: Reference to an opened filehandle
2026# $_[1]: Command byte (usually register number)
2027# $_[2]: Byte to write
2028# Returns: -1 on failure, 0 on success.
2029sub i2c_smbus_write_byte_data
2030{
2031  my ($file,$command,$value) = @_;
2032  my $data = [$value];
2033  i2c_smbus_access $file, $SMBUS_WRITE, $command, $SMBUS_BYTE_DATA, $data 
2034         or return -1;
2035  return 0;
2036}
2037
2038# $_[0]: Reference to an opened filehandle
2039# $_[1]: Command byte (usually register number)
2040# Returns: -1 on failure, the read word on success.
2041# Note: some devices use the wrong endiannes; use swap_bytes to correct for
2042# this.
2043sub i2c_smbus_read_word_data
2044{
2045  my ($file,$command) = @_;
2046  my $data = [];
2047  i2c_smbus_access $file, $SMBUS_READ, $command, $SMBUS_WORD_DATA, $data 
2048         or return -1;
2049  return $$data[0] + 256 * $$data[1];
2050}
2051
2052# $_[0]: Reference to an opened filehandle
2053# $_[1]: Command byte (usually register number)
2054# $_[2]: Byte to write
2055# Returns: -1 on failure, 0 on success.
2056# Note: some devices use the wrong endiannes; use swap_bytes to correct for
2057# this.
2058sub i2c_smbus_write_word_data
2059{
2060  my ($file,$command,$value) = @_;
2061  my $data = [$value & 0xff, $value >> 8];
2062  i2c_smbus_access $file, $SMBUS_WRITE, $command, $SMBUS_WORD_DATA, $data 
2063         or return -1;
2064  return 0;
2065}
2066
2067# $_[0]: Reference to an opened filehandle
2068# $_[1]: Command byte (usually register number)
2069# $_[2]: Word to write
2070# Returns: -1 on failure, read word on success.
2071# Note: some devices use the wrong endiannes; use swap_bytes to correct for
2072# this.
2073sub i2c_smbus_process_call
2074{
2075  my ($file,$command,$value) = @_;
2076  my $data = [$value & 0xff, $value >> 8];
2077  i2c_smbus_access $file, $SMBUS_WRITE, $command, $SMBUS_PROC_CALL, $data 
2078         or return -1;
2079  return $$data[0] + 256 * $$data[1];
2080}
2081
2082# $_[0]: Reference to an opened filehandle
2083# $_[1]: Command byte (usually register number)
2084# Returns: Undefined on failure, a list of read bytes on success
2085# Note: some devices use the wrong endiannes; use swap_bytes to correct for
2086# this.
2087sub i2c_smbus_read_block_data
2088{
2089  my ($file,$command) = @_;
2090  my $data = [];
2091  i2c_smbus_access $file, $SMBUS_READ, $command, $SMBUS_BLOCK_DATA, $data 
2092         or return;
2093  shift @$data;
2094  return @$data;
2095}
2096
2097# $_[0]: Reference to an opened filehandle
2098# $_[1]: Command byte (usually register number)
2099# @_[2..]: List of values to write
2100# Returns: -1 on failure, 0 on success.
2101# Note: some devices use the wrong endiannes; use swap_bytes to correct for
2102# this.
2103sub i2c_smbus_write_block_data
2104{
2105  my ($file,$command,@data) = @_;
2106  i2c_smbus_access $file, $SMBUS_WRITE, $command, $SMBUS_BLOCK_DATA, \@data 
2107         or return;
2108  return 0;
2109}
2110
2111####################
2112# ADAPTER SCANNING #
2113####################
2114
2115use vars qw(@chips_detected);
2116
2117# We will build a complicated structure @chips_detected here, being:
2118# A list of
2119#  references to hashes
2120#    with field 'driver', being a string with the driver name for this chip;
2121#    with field 'detected'
2122#      being a reference to a list of
2123#        references to hashes of type 'detect_data';
2124#    with field 'misdetected'
2125#      being a reference to a list of
2126#        references to hashes of type 'detect_data'
2127
2128# Type detect_data:
2129# A hash
2130#   with field 'i2c_adap' containing an adapter string as appearing
2131#        in /proc/bus/i2c (if this is an I2C detection)
2132#  with field 'i2c_algo' containing an algorithm string as appearing
2133#       in /proc/bus/i2c (if this is an I2C detection)
2134#  with field 'i2c_devnr', contianing the /dev/i2c-* number of this
2135#       adapter (if this is an I2C detection)
2136#  with field 'i2c_driver', containing the driver name for this adapter
2137#       (if this is an I2C detection)
2138#  with field 'i2c_addr', containing the I2C address of the detection;
2139#       (if this is an I2C detection)
2140#  with field 'i2c_sub_addrs', containing a reference to a list of
2141#       other I2C addresses (if this is an I2C detection)
2142#  with field 'i2c_extra' if this is an I2C detection and the address
2143#       is not normally probed by the kernel driver
2144#  with field 'isa_addr' containing the ISA address this chip is on
2145#       (if this is an ISA detection)
2146#  with field 'isa_extra' if this is an ISA detection and the address
2147#       is not normally probed by the kernel driver
2148#  with field 'conf', containing the confidence level of this detection
2149#  with field 'chipname', containing the chip name
2150
2151# This adds a detection to the above structure. We do no alias detection
2152# here; so you should do ISA detections *after* all I2C detections.
2153# Not all possibilities of i2c_addr and i2c_sub_addrs are exhausted.
2154# In all normal cases, it should be all right.
2155# $_[0]: chip driver
2156# $_[1]: reference to data hash
2157# Returns: Nothing
2158sub add_i2c_to_chips_detected
2159{
2160  my ($chipdriver,$datahash) = @_;
2161  my ($i,$new_detected_ref,$new_misdetected_ref,$detected_ref,$misdetected_ref,
2162      $main_entry,$detected_entry,$put_in_detected,@hash_addrs,@entry_addrs,
2163      $do_not_add);
2164
2165  # First determine where the hash has to be added.
2166  for ($i = 0; $i < @chips_detected; $i++) {
2167    last if ($chips_detected[$i]->{driver} eq $chipdriver);
2168  }
2169  if ($i == @chips_detected) {
2170    push @chips_detected, { driver => $chipdriver,
2171                            detected => [],
2172                            misdetected => [] };
2173  }
2174  $new_detected_ref = $chips_detected[$i]->{detected};
2175  $new_misdetected_ref = $chips_detected[$i]->{misdetected};
2176
2177  # Find out whether our new entry should go into the detected or the
2178  # misdetected list. We compare all i2c addresses; if at least one matches,
2179  # but our conf value is lower, we assume this is a misdetect.
2180  @hash_addrs = ($datahash->{i2c_addr});
2181  push @hash_addrs, @{$datahash->{i2c_sub_addrs}}
2182       if exists $datahash->{i2c_sub_addrs};
2183  $put_in_detected = 1;
2184  $do_not_add = 0;
2185  FIND_LOOP:
2186  foreach $main_entry (@chips_detected) {
2187    foreach $detected_entry (@{$main_entry->{detected}}) {
2188      @entry_addrs = ($detected_entry->{i2c_addr});
2189      push @entry_addrs, @{$detected_entry->{i2c_sub_addrs}}
2190               if exists $detected_entry->{i2c_sub_addrs};
2191      if ($detected_entry->{i2c_devnr} == $datahash->{i2c_devnr} and
2192          any_list_match \@entry_addrs, \@hash_addrs) {
2193        if ($detected_entry->{conf} >= $datahash->{conf}) {
2194          $put_in_detected = 0;
2195        }
2196        if ($chipdriver eq $main_entry->{driver}) {
2197          $do_not_add = 1;
2198        }
2199        last FIND_LOOP;
2200      }
2201    }
2202  }
2203
2204  if ($put_in_detected) {
2205    # Here, we move all entries from detected to misdetected which
2206    # match at least in one main or sub address. This may not be the
2207    # best idea to do, as it may remove detections without replacing
2208    # them with second-best ones. Too bad.
2209    # (Khali 2003-09-13) If the driver is the same, the "misdetected"
2210    # entry is simply deleted; failing to do so cause the configuration
2211    # lines generated later to look very confusing (the driver will
2212    # be told to ignore valid addresses).
2213    @hash_addrs = ($datahash->{i2c_addr});
2214    push @hash_addrs, @{$datahash->{i2c_sub_addrs}} 
2215         if exists $datahash->{i2c_sub_addrs};
2216    foreach $main_entry (@chips_detected) {
2217      $detected_ref = $main_entry->{detected};
2218      $misdetected_ref = $main_entry->{misdetected};
2219      for ($i = @$detected_ref-1; $i >=0; $i--) {
2220        @entry_addrs = ($detected_ref->[$i]->{i2c_addr});
2221        push @entry_addrs, @{$detected_ref->[$i]->{i2c_sub_addrs}}
2222             if exists $detected_ref->[$i]->{i2c_sub_addrs};
2223        if ($detected_ref->[$i]->{i2c_devnr} == $datahash->{i2c_devnr} and
2224            any_list_match \@entry_addrs, \@hash_addrs) {
2225          push @$misdetected_ref,$detected_ref->[$i]
2226            unless $chipdriver eq $main_entry->{driver};
2227          splice @$detected_ref, $i, 1;
2228        }
2229      }
2230    }
2231
2232    # Now add the new entry to detected
2233    push @$new_detected_ref, $datahash;
2234  } else {
2235    # No hard work here
2236    push @$new_misdetected_ref, $datahash
2237      unless $do_not_add;
2238  }
2239}
2240
2241# This adds a detection to the above structure. We also do alias detection
2242# here; so you should do ISA detections *after* all I2C detections.
2243# $_[0]: alias detection function
2244# $_[1]: chip driver
2245# $_[2]: reference to data hash
2246# Returns: 0 if it is not an alias, datahash reference if it is.
2247sub add_isa_to_chips_detected
2248{
2249  my ($alias_detect,$chipdriver,$datahash) = @_;
2250  my ($i,$new_detected_ref,$new_misdetected_ref,$detected_ref,$misdetected_ref,
2251      $main_entry,$isalias);
2252
2253  # First determine where the hash has to be added.
2254  $isalias=0;
2255  for ($i = 0; $i < @chips_detected; $i++) {
2256    last if ($chips_detected[$i]->{driver} eq $chipdriver);
2257  }
2258  if ($i == @chips_detected) {
2259    push @chips_detected, { driver => $chipdriver,
2260                            detected => [],
2261                            misdetected => [] };
2262  }
2263  $new_detected_ref = $chips_detected[$i]->{detected};
2264  $new_misdetected_ref = $chips_detected[$i]->{misdetected};
2265
2266  # Now, we are looking for aliases. An alias can only be the same chiptype.
2267  # If an alias is found in the misdetected list, we add the new information
2268  # and terminate this function. If it is found in the detected list, we
2269  # still have to check whether another chip has claimed this ISA address.
2270  # So we remove the old entry from the detected list and put it in datahash.
2271
2272  # Misdetected alias detection:
2273  for ($i = 0; $i < @$new_misdetected_ref; $i++) {
2274    if (exists $new_misdetected_ref->[$i]->{i2c_addr} and
2275        not exists $new_misdetected_ref->[$i]->{isa_addr} and
2276        defined $alias_detect and
2277        $new_misdetected_ref->[$i]->{chipname} eq $datahash->{chipname}) {
2278      open FILE,"$dev_i2c$new_misdetected_ref->[$i]->{i2c_devnr}" or
2279        print("Can't open $dev_i2c$new_misdetected_ref->[$i]->{i2c_devnr}?!?\n"),
2280        next;
2281      binmode FILE;
2282      i2c_set_slave_addr \*FILE,$new_misdetected_ref->[$i]->{i2c_addr} or
2283           print("Can't set I2C address for ",
2284                 "$dev_i2c$new_misdetected_ref->[$i]->{i2c_devnr}?!?\n"),
2285           next;
2286      if (&$alias_detect ($datahash->{isa_addr},\*FILE,
2287                          $new_misdetected_ref->[$i]->{i2c_addr})) {
2288        $new_misdetected_ref->[$i]->{isa_addr} = $datahash->{isa_addr};
2289        $new_misdetected_ref->[$i]->{isa_extra} = $datahash->{isa_extra} 
2290               if exists $datahash->{isa_extra};
2291        close FILE;
2292        return $new_misdetected_ref->[$i]; 
2293      }
2294      close FILE;
2295    }
2296  }
2297
2298  # Detected alias detection:
2299  for ($i = 0; $i < @$new_detected_ref; $i++) {
2300    if (exists $new_detected_ref->[$i]->{i2c_addr} and
2301        not exists $new_detected_ref->[$i]->{isa_addr} and
2302        defined $alias_detect and
2303        $new_detected_ref->[$i]->{chipname} eq $datahash->{chipname}) {
2304      open FILE,"$dev_i2c$new_detected_ref->[$i]->{i2c_devnr}" or
2305        print("Can't open $dev_i2c$new_detected_ref->[$i]->{i2c_devnr}?!?\n"),
2306        next;
2307      binmode FILE;
2308      i2c_set_slave_addr \*FILE,$new_detected_ref->[$i]->{i2c_addr} or
2309           print("Can't set I2C address for ",
2310                 "$dev_i2c$new_detected_ref->[$i]->{i2c_devnr}?!?\n"),
2311           next;
2312      if (&$alias_detect ($datahash->{isa_addr},\*FILE,
2313                          $new_detected_ref->[$i]->{i2c_addr})) {
2314        $new_detected_ref->[$i]->{isa_addr} = $datahash->{isa_addr};
2315        $new_detected_ref->[$i]->{isa_extra} = $datahash->{isa_extra} 
2316               if exists $datahash->{isa_extra};
2317        ($datahash) = splice (@$new_detected_ref, $i, 1);
2318        close FILE;
2319        $isalias=1;
2320        last;
2321      }
2322      close FILE;
2323    }
2324  }
2325
2326
2327  # Find out whether our new entry should go into the detected or the
2328  # misdetected list. We only compare main isa_addr here, of course.
2329  foreach $main_entry (@chips_detected) {
2330    $detected_ref = $main_entry->{detected};
2331    $misdetected_ref = $main_entry->{misdetected};
2332    for ($i = 0; $i < @{$main_entry->{detected}}; $i++) {
2333      if (exists $detected_ref->[$i]->{isa_addr} and
2334          $detected_ref->[$i]->{isa_addr} == $datahash->{isa_addr}) {
2335        if ($detected_ref->[$i]->{conf} >= $datahash->{conf}) {
2336          push @$new_misdetected_ref, $datahash;
2337        } else {
2338          push @$misdetected_ref,$detected_ref->[$i];
2339          splice @$detected_ref, $i,1;
2340          push @$new_detected_ref, $datahash;
2341        }
2342        if ($isalias) {
2343          return $datahash;
2344        } else {
2345          return 0;
2346        }
2347      }
2348    }
2349  }
2350
2351  # Not found? OK, put it in the detected list
2352  push @$new_detected_ref, $datahash;
2353  if ($isalias) {
2354    return $datahash;
2355  } else {
2356    return 0;
2357  }
2358}
2359
2360# $_[0]: The number of the adapter to scan
2361# $_[1]: The name of the adapter, as appearing in /proc/bus/i2c
2362# $_[2]: The name of the algorithm, as appearing in /proc/bus/i2c
2363# $_[3]: The driver of the adapter
2364# @_[4..]: Addresses not to scan
2365sub scan_adapter
2366{
2367  my ( $adapter_nr,$adapter_name,$algorithm_name,$adapter_driver, 
2368       $not_to_scan) = @_;
2369  my ($chip, $addr, $conf,@chips,$new_hash,$other_addr);
2370
2371  # As we modify it, we need a copy
2372  my @not_to_scan = @$not_to_scan;
2373
2374  open FILE,"$dev_i2c$adapter_nr" or 
2375    (print "Can't open $dev_i2c$adapter_nr\n"), return;
2376  binmode FILE;
2377
2378  # Now scan each address in turn
2379  foreach $addr (0x03..0x77) {
2380    # As the not_to_scan list is sorted, we can check it fast
2381    if (@not_to_scan and $not_to_scan[0] == $addr) {
2382      shift @not_to_scan;
2383      next;
2384    }
2385
2386    i2c_set_slave_addr(\*FILE,$addr) or 
2387        printf("Client at address 0x%02x can not be probed - unload all client drivers first!\n",$addr), next;
2388
2389    next unless i2c_smbus_write_quick(\*FILE,$SMBUS_WRITE) >= 0;
2390    printf "Client found at address 0x%02x\n",$addr;
2391    # Prevent 24RF08 corruption
2392    if($addr >= 0x54 and $addr <= 0x57) {
2393        i2c_smbus_write_quick(\*FILE,$SMBUS_WRITE);
2394    }
2395
2396    foreach $chip (@chip_ids) {
2397      if (exists $$chip{i2c_addrs} and contains $addr, @{$$chip{i2c_addrs}}) {
2398        print "Probing for `$$chip{name}'... ";
2399        if (($conf,@chips) = &{$$chip{i2c_detect}} (\*FILE ,$addr)) {
2400          print "Success!\n",
2401                "    (confidence $conf, driver `$$chip{driver}')";
2402          if (@chips) {
2403            print ", other addresses:";
2404            @chips = sort @chips;
2405            foreach $other_addr (sort @chips) {
2406              printf(" 0x%02x",$other_addr);
2407            }
2408          }
2409          printf "\n";
2410          $new_hash = { conf => $conf,
2411                        i2c_addr => $addr,
2412                        chipname =>  $$chip{name},
2413                        i2c_adap => $adapter_name,
2414                        i2c_algo => $algorithm_name,
2415                        i2c_driver => $adapter_driver,
2416                        i2c_devnr => $adapter_nr,
2417                      };
2418          if (@chips) {
2419            my @chips_copy = @chips;
2420            $new_hash->{i2c_sub_addrs} = \@chips_copy;
2421          }
2422          $new_hash->{i2c_extra} = 0 
2423                 if exists $chip->{i2c_driver_addrs} and
2424                    not contains( $addr , @{$chip->{i2c_driver_addrs}});
2425          add_i2c_to_chips_detected $$chip{driver}, $new_hash;
2426        } else {
2427          print "Failed!\n";
2428        }
2429      }
2430    }
2431  }
2432}
2433
2434sub scan_isa_bus
2435{
2436  my ($chip,$addr,$conf);
2437  foreach $chip (@chip_ids) {
2438    next if not exists $$chip{isa_addrs} or not exists $$chip{isa_detect};
2439    print "Probing for `$$chip{name}'\n";
2440    foreach $addr (@{$$chip{isa_addrs}}) {
2441      if ($addr) {
2442        printf "  Trying address 0x%04x... ", $addr;
2443      } else {
2444        print "  Trying general detect... ";
2445      }
2446      $conf = &{$$chip{isa_detect}} ($addr);
2447      print("Failed!\n"), next if not defined $conf;
2448      print "Success!\n";
2449      printf "    (confidence %d, driver `%s')\n", $conf, $$chip{driver};
2450      my $new_hash = { conf => $conf,
2451                       isa_addr => $addr,
2452                       chipname =>  $$chip{name}
2453                     };
2454      $new_hash->{isa_extra} = 0 
2455             if exists $chip->{isa_driver_addrs} and
2456                not contains ($addr, @{$chip->{isa_driver_addrs}});
2457      $new_hash = add_isa_to_chips_detected $$chip{alias_detect},$$chip{driver},
2458                                            $new_hash;
2459      if ($new_hash) {
2460        printf "    Alias of the chip on I2C bus `%s', address 0x%04x\n",
2461                        $new_hash->{i2c_adap},$new_hash->{i2c_addr};
2462      }
2463    }
2464  }
2465}
2466
2467sub exit_superio
2468{
2469  my ($addrreg, $datareg, $family, $success) = @_;
2470
2471  # If detection succeeded and an exit sequence exists, use it
2472  if ($success && defined ($$family{exit})) {
2473    foreach my $byte (@{$$family{exit}}) {
2474      outb($addrreg, $byte);
2475    }
2476    return;
2477  }
2478
2479  # Else return to "Wait For Key" state (PNP-ISA spec)
2480  outb($addrreg, 0x02);
2481  outb($datareg, 0x02);
2482}
2483
2484# The following are taken from the PNP ISA spec (so it's supposed
2485# to be common to all Super I/0 chips):
2486#  devidreg: The device ID register(s)
2487#  logdevreg: The logical device register
2488#  actreg: The activation register within the logical device
2489#  actmask: The activation bit in the activation register
2490#  basereg: The I/O base register within the logical device
2491sub scan_superio
2492{
2493  my ($addrreg, $datareg) = @_;
2494  my ($val, $addr);
2495
2496  my %superio = (
2497    devidreg => 0x20,
2498    logdevreg => 0x07,
2499    actreg => 0x30,
2500    actmask => 0x01,
2501    basereg => 0x60,
2502  );
2503 
2504  FAMILY:
2505  foreach my $family (@superio_ids) {
2506# write the password
2507    foreach $val (@{$$family{enter}}) {
2508      outb($addrreg, $val);
2509    }
2510    foreach my $chip (@{$$family{chips}}) {
2511      print "Probing for `$$chip{name}'\n";
2512# check the device ID
2513      outb($addrreg, $superio{devidreg});
2514      $val = inb($datareg);
2515      if ($val == 0x00 || $val == 0xff) {
2516        print "  Failed! (skipping family)\n";
2517        exit_superio($addrreg, $datareg, $family, 0);
2518        next FAMILY;
2519      }
2520      if ($$chip{devid}>0xff) {
2521        outb($addrreg, $superio{devidreg} + 1);
2522        $val = ($val << 8) | inb($datareg);
2523      }
2524      if ($val != $$chip{devid}) {
2525        printf "  Failed! (0x%02x)\n", $val;
2526        next;
2527      }
2528      print "  Success...";
2529# does it have hardware monitoring capabilities
2530      if($$chip{driver} eq "not-a-sensor") {
2531        print " (no hardware monitoring capabilities)\n";
2532        next;
2533      }
2534# switch to the sensor logical device
2535      outb($addrreg, $superio{logdevreg});
2536      outb($datareg, $$chip{logdev});
2537# check the activation register
2538      outb($addrreg, $superio{actreg});
2539      $val = inb($datareg);
2540      if(!($val & $superio{actmask})) {
2541        print " but not activated\n";
2542        next;
2543      }
2544# Get the IO base register
2545      outb($addrreg, $superio{basereg});
2546      $addr = inb($datareg);
2547      outb($addrreg, $superio{basereg} + 1);
2548      $addr = ($addr << 8) | inb($datareg);
2549      if($addr == 0) {
2550        print " but no address specified\n";
2551        next;
2552      }         
2553      printf " found at address 0x%04x\n", $addr;
2554      my $new_hash = { conf => 9,
2555                       isa_addr => $addr,
2556                       chipname =>  $$chip{name}
2557                     };
2558      add_isa_to_chips_detected $$chip{alias_detect},$$chip{driver},
2559                                            $new_hash;
2560    }
2561    exit_superio($addrreg, $datareg, $family, 1);
2562  }
2563}
2564
2565
2566##################
2567# CHIP DETECTION #
2568##################
2569
2570# Each function returns a confidence value. The higher this value, the more
2571# sure we are about this chip. A Winbond W83781D, for example, will be
2572# detected as a LM78 too; but as the Winbond detection has a higher confidence
2573# factor, you should identify it as a Winbond.
2574
2575# Each function returns a list. The first element is the confidence value;
2576# Each element after it is an SMBus address. In this way, we can detect
2577# chips with several SMBus addresses. The SMBus address for which the
2578# function was called is never returned.
2579
2580# If there are devices which get confused if they are only read from, then
2581# this program will surely confuse them. But we guarantee never to write to
2582# any of these devices.
2583
2584
2585# $_[0]: A reference to the file descriptor to access this chip.
2586#        We may assume an i2c_set_slave_addr was already done.
2587# $_[1]: Address
2588# Returns: undef if not detected, (7) if detected.
2589# Registers used: 0x58
2590sub mtp008_detect
2591{
2592  my ($file,$addr) = @_;
2593  return if (i2c_smbus_read_byte_data($file,0x58)) != 0xac;
2594  return (8);
2595}
2596 
2597# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
2598# $_[1]: A reference to the file descriptor to access this chip.
2599#        We may assume an i2c_set_slave_addr was already done.
2600# $_[2]: Address
2601# Returns: undef if not detected, (6) if detected.
2602# Registers used:
2603#   0x40: Configuration
2604#   0x48: Full I2C Address
2605#   0x49: Device ID
2606# Note that this function is always called through a closure, so the
2607# arguments are shifted by one place.
2608sub lm78_detect
2609{
2610  my $reg;
2611  my ($chip,$file,$addr) = @_;
2612  return unless i2c_smbus_read_byte_data($file,0x48) == $addr;
2613  return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
2614  $reg = i2c_smbus_read_byte_data($file,0x49);
2615  return unless ($chip == 0 and ($reg == 0x00 or $reg == 0x20)) or
2616                    ($chip == 1 and $reg == 0x40) or
2617                    ($chip == 2 and ($reg & 0xfe) == 0xc0);
2618  return (6);
2619}
2620
2621# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
2622# $_[1]: Address
2623# Returns: undef if not detected, 7 if detected.
2624# Note: Only address 0x290 is scanned at this moment.
2625sub lm78_isa_detect
2626{
2627  my ($chip,$addr) = @_ ;
2628  my $val = inb ($addr + 1);
2629  return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or 
2630            inb ($addr + 7) != $val;
2631
2632  $val = inb($addr + 5) & 0x7f;
2633  outb($addr + 5, ~$val & 0xff);
2634  if ((inb ($addr+5) & 0x7f) != (~ $val & 0x7f)) {
2635    outb($addr+5,$val);
2636    return;
2637  }
2638  my $readproc = sub { isa_read_byte $addr + 5, $addr + 6, @_ };
2639  return unless (&$readproc(0x40) & 0x80) == 0x00;
2640  my $reg = &$readproc(0x49);
2641  return unless ($chip == 0 and ($reg == 0x00 or $reg == 0x20)) or
2642                ($chip == 1 and $reg == 0x40) or
2643                ($chip == 2 and ($reg & 0xfe) == 0xc0);
2644  return 7;
2645}
2646
2647
2648# $_[0]: Chip to detect (0 = LM78, 1 = LM78-J, 2 = LM79)
2649# $_[1]: ISA address
2650# $_[2]: I2C file handle
2651# $_[3]: I2C address
2652sub lm78_alias_detect
2653{
2654  my ($chip,$isa_addr,$file,$i2c_addr) = @_;
2655  my $i;
2656  my $readproc = sub { isa_read_byte $isa_addr + 5, $isa_addr + 6, @_ };
2657  return 0 unless &$readproc(0x48) == $i2c_addr;
2658  for ($i = 0x2b; $i <= 0x3d; $i ++) {
2659    return 0 unless &$readproc($i) == i2c_smbus_read_byte_data($file,$i);
2660  }
2661  return 1;
2662}
2663
2664# $_[0]: A reference to the file descriptor to access this chip.
2665#        We may assume an i2c_set_slave_addr was already done.
2666# $_[1]: Address
2667# Returns: undef if not detected, 2 to 6 if detected;
2668#   6 means that the LM75 was found in its default power up state;
2669#   5 means that the LM75 was found in another known default state;
2670#   4 means that the LM75 was found in a probable state (temperatures
2671#       make sense);
2672#   3 means that the configuration register passes the test;
2673# Registers used:
2674#   0x00: Temperature
2675#   0x01: Configuration
2676#   0x02: Hysteresis
2677#   0x03: Overtemperature Shutdown
2678# The first detection step is only based on the fact that the LM75 has only
2679# four registers. Any other chip in the valid address range with only four
2680# registers will be detected too.
2681# Note that register $00 may change, so we can't use the modulo trick on it.
2682sub lm75_detect
2683{
2684  my $i;
2685  my ($file,$addr) = @_;
2686  my $cur = i2c_smbus_read_word_data($file,0x00);
2687  my $cur_varies = 0;
2688  my $conf = i2c_smbus_read_byte_data($file,0x01);
2689  my $hyst = i2c_smbus_read_word_data($file,0x02);
2690  my $os = i2c_smbus_read_word_data($file,0x03);
2691  for ($i = 0x00; $i <= 0x1f; $i += 1) {
2692    return if i2c_smbus_read_byte_data($file,($i * 0x08) + 0x01) != $conf;
2693    return if i2c_smbus_read_word_data($file,($i * 0x08) + 0x02) != $hyst;
2694    return if i2c_smbus_read_word_data($file,($i * 0x08) + 0x03) != $os;
2695        $cur_varies = 1
2696      if (! $cur_varies) and
2697        i2c_smbus_read_word_data($file,($i * 0x08)) != $cur;
2698  }
2699  # Default power up state (from specs)
2700  return 6
2701    if $conf == 0 and ($hyst&0x80ff) == 0x004b and ($os&0x80ff) == 0x0050;
2702  # Default state as seen on the Asus TX97-E
2703  return 5
2704    if $conf == 0 and ($hyst&0x80ff) == 0x002d and ($os&0x80ff) == 0x0034;
2705  # All registers hold the same value, obviously a misdetection
2706  return
2707    if (! $cur_varies) and $conf == ($cur&0xff) and $cur == $hyst
2708      and $cur == $os;
2709  # Unused bits in conf register
2710  return
2711    if ($conf&0xe0) != 0;
2712  # Most probable value ranges
2713  return 4
2714    if (($cur&0x00ff) <= 125 || ($cur&0x00ff) >= 201)
2715       and ($hyst&0x00ff) <= 125 and ($os&0x00ff) <= 125 and $hyst<$os;
2716  return 3;
2717}
2718
2719# $_[0]: Chip to detect (0 = LM92, 1 = LM76, 2 = MAX6633/MAX6634/MAX6635)
2720# $_[1]: A reference to the file descriptor to access this chip.
2721#        We may assume an i2c_set_slave_addr was already done.
2722# $_[2]: Address
2723# Returns: undef if not detected, 2 or 4 if detected;
2724# Registers used:
2725#   0x01: Configuration (National Semiconductor only)
2726#   0x02: Hysteresis
2727#   0x03: Critical Temp
2728#   0x04: Low Limit
2729#   0x05: High Limit
2730#   0x07: Manufacturer ID (LM92 only)
2731# One detection step is based on the fact that the LM92 and clones have a
2732# limited number of registers, which cycle modulo 16 address values.
2733# Note that register 0x00 may change, so we can't use the modulo trick on it.
2734sub lm92_detect
2735{
2736  my ($chip, $file, $addr) = @_;
2737
2738  my $cur = i2c_smbus_read_word_data($file, 0x00);
2739  my $conf = i2c_smbus_read_byte_data($file, 0x01);
2740  my $hyst = i2c_smbus_read_word_data($file, 0x02);
2741  my $crit = i2c_smbus_read_word_data($file, 0x03);
2742  my $low = i2c_smbus_read_word_data($file, 0x04);
2743  my $high = i2c_smbus_read_word_data($file, 0x05);
2744
2745  return if $chip == 0
2746        and i2c_smbus_read_word_data($file, 0x07) != 0x0180;
2747 
2748  return if ($chip == 0 || $chip == 1)
2749        and ($conf & 0xE0);
2750
2751  for (my $i = 0; $i < 8; $i++) {
2752    return if i2c_smbus_read_byte_data($file, $i*16+0x01) != $conf;
2753    return if i2c_smbus_read_word_data($file, $i*16+0x02) != $hyst;
2754    return if i2c_smbus_read_word_data($file, $i*16+0x03) != $crit;
2755    return if i2c_smbus_read_word_data($file, $i*16+0x04) != $low;
2756    return if i2c_smbus_read_word_data($file, $i*16+0x05) != $high;
2757  }
2758 
2759  foreach my $temp ($hyst, $crit, $low, $high) {
2760    return if $chip == 2 and ($temp & 0x7F00);
2761    return if $chip != 2 and ($temp & 0x0700);
2762  }
2763
2764  return 4 if $chip == 0;
2765  return 2;
2766}
2767 
2768# $_[0]: A reference to the file descriptor to access this chip.
2769#        We may assume an i2c_set_slave_addr was already done.
2770# $_[1]: Address
2771# Returns: undef if not detected, (3) if detected,
2772#   (5) or (7) if even more bits match.
2773# Registers used:
2774#   0xAA: Temperature
2775#   0xA1: High limit
2776#   0xA2: Low limit
2777#   0xAC: Configuration
2778# Detection is weak. We check if Bit 3 is set and Bit 2 is clear.
2779# The DS1621 will aways have a config like 0x????10??. A even better
2780# match would be 0x0??01000.
2781# Temperature checkings will hopefully prevent LM75 chips from being
2782# detected as a DS1621.
2783sub ds1621_detect
2784{
2785  my $i;
2786  my ($file,$addr) = @_;
2787  my $temp = i2c_smbus_read_word_data($file,0xAA);
2788  return if ($temp & 0x007F);
2789  $temp = i2c_smbus_read_word_data($file,0xA1);
2790  return if ($temp & 0x007F);
2791  $temp = i2c_smbus_read_word_data($file,0xA2);
2792  return if ($temp & 0x007F);
2793  my $conf = i2c_smbus_read_byte_data($file,0xAC);
2794  return (7) if ($conf & 0x9F) == 0x98;
2795  return (5) if ($conf & 0x0F) == 0x08;
2796  return (3) if ($conf & 0x0C) == 0x08;
2797  return ;
2798}
2799
2800# $_[0]: A reference to the file descriptor to access this chip.
2801#        We may assume an i2c_set_slave_addr was already done.
2802# $_[1]: Address
2803# Returns: undef if not detected, 1 to 3 if detected.
2804# Registers used:
2805#   0x00: Configuration register
2806#   0x02: Interrupt state register
2807#   0x2a-0x3d: Limits registers
2808# This one is easily misdetected since it doesn't provide identification
2809# registers. So we have to use some tricks:
2810#   - 6-bit addressing, so limits readings modulo 0x40 should be unchanged
2811#   - positive temperature limits
2812#   - limits order correctness
2813# Hopefully this should limit the rate of false positives, without increasing
2814# the rate of false negatives.
2815# Thanks to Lennard Klein for testing on a non-LM80 chip, which was
2816# previously misdetected, and isn't anymore. For reference, it scored
2817# a final confidence of 0, and changing from strict limit comparisons
2818# to loose comparisons did not change the score.
2819sub lm80_detect
2820{
2821  my ($i,$reg);
2822  my ($file,$addr) = @_;
2823
2824  return if (i2c_smbus_read_byte_data($file,0x00) & 0x80) != 0;
2825  return if (i2c_smbus_read_byte_data($file,0x02) & 0xc0) != 0;
2826
2827  for ($i = 0x2a; $i <= 0x3d; $i++) {
2828    $reg = i2c_smbus_read_byte_data($file,$i);
2829    return if i2c_smbus_read_byte_data($file,$i+0x40) != $reg;
2830    return if i2c_smbus_read_byte_data($file,$i+0x80) != $reg;
2831    return if i2c_smbus_read_byte_data($file,$i+0xc0) != $reg;
2832  }
2833 
2834  # Refine a bit by checking wether limits are in the correct order
2835  # (min<max for voltages, hyst<max for temperature). Since it is still
2836  # possible that the chip is an LM80 with limits not properly set,
2837  # a few "errors" are tolerated.
2838  my $confidence = 0;
2839  for ($i = 0x2a; $i <= 0x3a; $i++) {
2840    $confidence++
2841      if i2c_smbus_read_byte_data($file,$i) < i2c_smbus_read_byte_data($file,$i+1);
2842  }
2843  # hot temp<OS temp
2844  $confidence++
2845    if i2c_smbus_read_byte_data($file,0x38) < i2c_smbus_read_byte_data($file,0x3a);
2846
2847  # Negative temperature limits are unlikely.
2848  for ($i = 0x3a; $i <= 0x3d; $i++) {
2849    $confidence++ if (i2c_smbus_read_byte_data($file,$i) & 0x80) == 0;
2850  }
2851
2852  # $confidence is between 0 and 14
2853  $confidence = ($confidence >> 1) - 4;
2854  # $confidence is now between -4 and 3
2855
2856  return unless $confidence > 0;
2857
2858  return $confidence;
2859}
2860
2861# $_[0]: Chip to detect
2862#   (0 = LM83, 1 = LM82)
2863# $_[1]: A reference to the file descriptor to access this chip.
2864#        We may assume an i2c_set_slave_addr was already done.
2865# $_[2]: Address
2866# Returns: undef if not detected, 5 to 8 if detected.
2867# Registers used:
2868#   0x02: Status 1
2869#   0x03: Configuration
2870#   0x04: Company ID of LM84
2871#   0x35: Status 2
2872#   0xfe: Manufacturer ID
2873#   0xff: Chip ID / die revision
2874# We can use the LM84 Company ID register because the LM83 and the LM82 are
2875# compatible with the LM84.
2876# The LM83 chip ID is missing from the datasheet and was contributed by
2877# Magnus Forsstrom.
2878sub lm83_detect
2879{
2880  my ($chip, $file) = @_;
2881  return if i2c_smbus_read_byte_data($file,0xfe) != 0x01;
2882  return if $chip == 0 and i2c_smbus_read_byte_data($file,0xff) != 0x03;
2883  return if $chip == 1 and i2c_smbus_read_byte_data($file,0xff) != 0x01;
2884
2885  my $confidence = 4;
2886  $confidence++
2887    if (i2c_smbus_read_byte_data($file,0x02) & 0xa8) == 0x00;
2888  $confidence++
2889    if (i2c_smbus_read_byte_data($file,0x03) & 0x41) == 0x00;
2890  $confidence++
2891    if i2c_smbus_read_byte_data($file,0x04) == 0x00;
2892  $confidence++
2893    if $chip == 0
2894    && (i2c_smbus_read_byte_data($file,0x35) & 0x48) == 0x00;
2895
2896  return $confidence;
2897}
2898
2899# $_[0]: Chip to detect
2900#   (0 = LM90, 1=LM89, 2=LM86, 3=ADM1032, 4=MAX6657/MAX6658,
2901#    5 = ADT7461)
2902# $_[1]: A reference to the file descriptor to access this chip.
2903#        We may assume an i2c_set_slave_addr was already done.
2904# $_[2]: Address
2905# Returns: undef if not detected, 3, 7 or 8 if detected.
2906#   The Maxim chips have a low confidence value (3)
2907#   because the die revision codes are not known.
2908# Registers used:
2909#   0x03: Configuration
2910#   0xfe: Manufacturer ID
2911#   0xff: Chip ID / die revision
2912sub lm90_detect
2913{
2914  my ($chip, $file, $addr) = @_;
2915  my $mid = i2c_smbus_read_byte_data($file, 0xfe);
2916  my $cid = i2c_smbus_read_byte_data($file, 0xff);
2917  my $conf = i2c_smbus_read_byte_data($file, 0x03);
2918
2919  if ($chip == 0) {
2920    return if ($conf & 0x2a) != 0;
2921        return if $mid != 0x01;     # National Semicondutor
2922    return 8 if $cid == 0x21;   # LM90
2923    return 7 if $cid > 0x21 and $cid < 0x30;
2924  }
2925  if ($chip == 1) {
2926    return if ($conf & 0x2a) != 0;
2927        return if $mid != 0x01;     # National Semicondutor
2928    return 8 if $cid == 0x31;   # LM89
2929    return 7 if $cid > 0x31 and $cid < 0x40;
2930  }
2931  if ($chip == 2) {
2932    return if ($conf & 0x2a) != 0;
2933        return if $mid != 0x01;     # National Semicondutor
2934    return 8 if $cid == 0x11;   # LM86
2935    return 7 if $cid > 0x11 and $cid < 0x20;
2936  }
2937  if ($chip == 3) {
2938    return if ($conf & 0x3f) != 0;
2939        return if $mid != 0x41;     # Analog Devices
2940        return 8 if ($cid & 0xf0) == 0x40; # ADM1032
2941  }
2942  if ($chip == 4) {
2943    return if ($conf & 0x1f) != 0;
2944        return if $mid != 0x4d;     # Maxim
2945        return 3;
2946  }
2947  if ($chip == 5) {
2948    return if ($conf & 0x1b) != 0;
2949    return if $mid != 0x41;     # Analog Devices
2950    return 8 if $cid == 0x61;   # ADT7461
2951  }
2952  return;
2953}
2954
2955# $_[0]: Chip to detect
2956#   (0 = ADM1029)
2957# $_[1]: A reference to the file descriptor to access this chip.
2958#        We may assume an i2c_set_slave_addr was already done.
2959# $_[2]: Address
2960# Returns: undef if not detected, 3 to 9 if detected.
2961# Registers used:
2962#   0x02, 0x03: Fan support
2963#   0x05: GPIO config
2964#   0x07, 0x08, 0x09: Fan config
2965#   0x0d: Manufacturer ID
2966#   0x0e: Chip ID / die revision
2967sub adm1029_detect
2968{
2969  my ($chip, $file, $addr) = @_;
2970  my $mid = i2c_smbus_read_byte_data($file, 0x0d);
2971  my $cid = i2c_smbus_read_byte_data($file, 0x0e);
2972  my $fansc = i2c_smbus_read_byte_data($file, 0x02);
2973  my $fanss = i2c_smbus_read_byte_data($file, 0x03);
2974  my $gpio = i2c_smbus_read_byte_data($file, 0x05);
2975  my $fanas = i2c_smbus_read_byte_data($file, 0x07);
2976  my $fanhps = i2c_smbus_read_byte_data($file, 0x08);
2977  my $fanfs = i2c_smbus_read_byte_data($file, 0x09);
2978  my $confidence = 3;
2979
2980  if ($chip == 0) {
2981    return if $mid != 0x41;     # Analog Devices
2982    $confidence++ if ($cid & 0xF0) == 0x00; # ADM1029
2983    $confidence+=2 if ($fansc & 0xFC) == 0x00
2984                   && ($fanss & 0xFC) == 0x00;
2985    $confidence+=2 if ($fanas & 0xFC) == 0x00
2986                   && ($fanhps & 0xFC) == 0x00
2987                   && ($fanfs & 0xFC) == 0x00;
2988    $confidence++ if ($gpio & 0x80) == 0x00;
2989    return $confidence;
2990  }
2991  return;
2992}
2993
2994# $_[0]: Chip to detect
2995#   (0 = ADM1030, 1=ADM1031)
2996# $_[1]: A reference to the file descriptor to access this chip.
2997#        We may assume an i2c_set_slave_addr was already done.
2998# $_[2]: Address
2999# Returns: undef if not detected, 3 to 7 (ADM1031) or 9 (ADM1030)
3000#          if detected.
3001# Registers used:
3002#   0x01: Config 2
3003#   0x03: Status 2
3004#   0x0d, 0x0e, 0x0f: Temperature offsets
3005#   0x22: Fan speed config
3006#   0x3d: Chip ID
3007#   0x3e: Manufacturer ID
3008#   0x3f: Die revision
3009sub adm1031_detect
3010{
3011  my ($chip, $file, $addr) = @_;
3012  my $mid = i2c_smbus_read_byte_data($file, 0x3e);
3013  my $cid = i2c_smbus_read_byte_data($file, 0x3d);
3014  my $drev = i2c_smbus_read_byte_data($file, 0x3f);
3015  my $conf2 = i2c_smbus_read_byte_data($file, 0x01);
3016  my $stat2 = i2c_smbus_read_byte_data($file, 0x03);
3017  my $fsc = i2c_smbus_read_byte_data($file, 0x22);
3018  my $lto = i2c_smbus_read_byte_data($file, 0x0d);
3019  my $r1to = i2c_smbus_read_byte_data($file, 0x0e);
3020  my $r2to = i2c_smbus_read_byte_data($file, 0x0f);
3021  my $confidence = 3;
3022
3023  if ($chip == 0) {
3024    return if $mid != 0x41;     # Analog Devices
3025    return if $cid != 0x30;     # ADM1030
3026    $confidence++ if ($drev & 0x70) == 0x00;
3027    $confidence++ if ($conf2 & 0x4A) == 0x00;
3028    $confidence++ if ($stat2 & 0x3F) == 0x00;
3029    $confidence++ if ($fsc & 0xF0) == 0x00;
3030    $confidence++ if ($lto & 0x70) == 0x00;
3031    $confidence++ if ($r1to & 0x70) == 0x00;
3032    return $confidence;
3033  }
3034  if ($chip == 1) {
3035    return if $mid != 0x41;     # Analog Devices
3036    return if $cid != 0x31;     # ADM1031
3037    $confidence++ if ($drev & 0x70) == 0x00;
3038    $confidence++ if ($lto & 0x70) == 0x00;
3039    $confidence++ if ($r1to & 0x70) == 0x00;
3040    $confidence++ if ($r2to & 0x70) == 0x00;
3041    return $confidence;
3042  }
3043  return;
3044}
3045
3046# $_[0]: Chip to detect
3047#   (0 = ADT7467)
3048# $_[1]: A reference to the file descriptor to access this chip.
3049#        We may assume an i2c_set_slave_addr was already done.
3050# $_[2]: Address
3051# Returns: undef if not detected, 5 if detected.
3052# Registers used:
3053#   0x3d: Chip ID
3054#   0x3e: Manufacturer ID
3055#   0x3f: Die revision
3056sub adt7467_detect
3057{
3058  my ($chip, $file, $addr) = @_;
3059  my $mid = i2c_smbus_read_byte_data($file, 0x3e);
3060  my $cid = i2c_smbus_read_byte_data($file, 0x3d);
3061  my $drev = i2c_smbus_read_byte_data($file, 0x3f);
3062
3063  if ($chip == 0) {
3064    return if $mid != 0x41;     # Analog Devices
3065    return if $cid != 0x68;     # ADT7467
3066    return if ($drev & 0xf0) != 0x70;
3067    return 5;
3068  }
3069  return
3070}
3071
3072# $_[0]: Vendor to check for
3073#   (0x01 = National Semi, 0x41 = Analog Dev, 0x5c = SMSC)
3074# $_[1]: A reference to the file descriptor to access this chip.
3075# #_[2]: Base address.
3076# Returns: undef if not detected, (7) or (8) if detected.
3077# Registers used: 0x3e == Vendor register.
3078#                 0x3d == Device ID register (Analog Devices only).
3079#                 0x3f == Version/Stepping register.
3080# Constants used: 0x01 == National Semiconductor Vendor Id.
3081#                 0x41 == Analog Devices Vendor Id.
3082#                 0x5c == SMSC Vendor Id.
3083#                 0x60 == Version number. The lower 4 stepping
3084#                         bits are masked and ignored.
3085sub lm85_detect
3086{
3087  my ($vendor,$file,$addr) = @_;
3088  return if (i2c_smbus_read_byte_data($file,0x3e)) != $vendor ;
3089  return if (i2c_smbus_read_byte_data($file,0x3f) & 0xf0) != 0x60;
3090
3091  if ($vendor == 0x41) # Analog Devices
3092  {
3093    return if i2c_smbus_read_byte_data($file, 0x3d) != 0x27;
3094    return (8);
3095  }
3096
3097  return (7);
3098}
3099
3100# $_[0]: A reference to the file descriptor to access this chip.
3101#        We may assume an i2c_set_slave_addr was already done.
3102# $_[1]: Address
3103# Returns: undef if not detected, (7) if detected.
3104# Registers used: 0x3E, 0x3F
3105#        Assume lower 2 bits of reg 0x3F are for revisions.
3106sub lm87_detect
3107{
3108  my ($file,$addr) = @_;
3109  return if (i2c_smbus_read_byte_data($file,0x3e)) != 0x02;
3110  return if (i2c_smbus_read_byte_data($file,0x3f) & 0xfc) != 0x04;
3111  return (7);
3112}
3113 
3114# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 2 = W83783S,
3115#                        3 = W83627HF, 4 = AS99127F (rev.1),
3116#                        5 = AS99127F (rev.2), 6 = ASB100, 7 = W83791D
3117# $_[1]: A reference to the file descriptor to access this chip.
3118#        We may assume an i2c_set_slave_addr was already done.
3119# $_[2]: Address
3120# Returns: undef if not detected, (8,addr1,addr2) if detected, but only
3121#          if the LM75 chip emulation is enabled.
3122# Registers used:
3123#   0x48: Full I2C Address
3124#   0x4a: I2C addresses of emulated LM75 chips
3125#   0x4e: Vendor ID byte selection, and bank selection
3126#   0x4f: Vendor ID
3127#   0x58: Device ID (only when in bank 0)
3128# Note: Fails if the W8378xD is not in bank 0!
3129# Note: Detection overrules a previous LM78 detection
3130# Note: Asus chips do not have their I2C address at register 0x48?
3131#       AS99127F rev.1 and ASB100 have 0x00, confirmation wanted for
3132#       AS99127F rev.2.
3133sub w83781d_detect
3134{
3135  my ($reg1,$reg2,@res);
3136  my ($chip,$file,$addr) = @_;
3137
3138  return unless (i2c_smbus_read_byte_data($file,0x48) == $addr)
3139    or ($chip >= 4 && $chip <= 6);
3140
3141  $reg1 = i2c_smbus_read_byte_data($file,0x4e);
3142  $reg2 = i2c_smbus_read_byte_data($file,0x4f);
3143  if ($chip == 4) { # Asus AS99127F (rev.1)
3144    return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xc3) or 
3145                  (($reg1 & 0x80) == 0x80 and $reg2 == 0x12);
3146  } elsif ($chip == 6) { # Asus ASB100
3147    return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0x94) or 
3148                  (($reg1 & 0x80) == 0x80 and $reg2 == 0x06);
3149  } else { # Winbond and Asus AS99127F (rev.2)
3150    return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or 
3151                  (($reg1 & 0x80) == 0x80 and $reg2 == 0x5c);
3152  }
3153
3154  return unless ($reg1 & 0x07) == 0x00;
3155
3156  $reg1 = i2c_smbus_read_byte_data($file,0x58);
3157  return if $chip == 0 and ($reg1 != 0x10 && $reg1 != 0x11);
3158  return if $chip == 1 and  $reg1 != 0x30;
3159  return if $chip == 2 and  $reg1 != 0x40;
3160  return if $chip == 3 and  $reg1 != 0x21;
3161  return if $chip == 4 and  $reg1 != 0x31;
3162  return if $chip == 5 and  $reg1 != 0x31;
3163  return if $chip == 6 and  $reg1 != 0x31;
3164  return if $chip == 7 and  $reg1 != 0x71;
3165  $reg1 = i2c_smbus_read_byte_data($file,0x4a);
3166  @res = (8);
3167  @res = (7) # Asus chips were always seen at 0x2d
3168    if ($chip >= 4 && $chip <= 6 && $addr != 0x2d);
3169  push @res, ($reg1 & 0x07) + 0x48 unless $reg1 & 0x08;
3170  push @res, (($reg1 & 0x70) >> 4) + 0x48 unless ($reg1 & 0x80 or $chip == 2);
3171  return @res;
3172}
3173
3174# $_[0]: Chip to detect (0 = ASM58, 1 = AS2K129R, 2 = ???)
3175# $_[1]: A reference to the file descriptor to access this chip
3176# $_[2]: Address (unused)
3177# Returns: undef if not detected, 5 if detected
3178# Registers used:
3179#   0x4e: Vendor ID high byte
3180#   0x4f: Vendor ID low byte
3181#   0x58: Device ID
3182# Note: The values were given by Alex van Kaam, we don't have datasheets
3183#       to confirm.
3184sub mozart_detect
3185{
3186  my ($vid,$dev);
3187  my ($chip,$file,$addr) = @_;
3188
3189  $vid = (i2c_smbus_read_byte_data($file,0x4e) << 8)
3190       +  i2c_smbus_read_byte_data($file,0x4f);
3191  $dev = i2c_smbus_read_byte_data($file,0x58);
3192
3193  return if ($chip == 0) and ($dev != 0x56 || $vid != 0x9436);
3194  return if ($chip == 1) and ($dev != 0x56 || $vid != 0x9406);
3195  return if ($chip == 2) and ($dev != 0x10 || $vid != 0x5ca3);
3196
3197  return 5;
3198}
3199
3200# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 2 = W83783S, 3 = W83627HF)
3201# $_[1]: ISA address
3202# $_[2]: I2C file handle
3203# $_[3]: I2C address
3204sub w83781d_alias_detect
3205{
3206  my ($chip,$isa_addr,$file,$i2c_addr) = @_;
3207  my $i;
3208  my $readproc = sub { isa_read_byte $isa_addr + 5, $isa_addr + 6, @_ };
3209  return 0 unless &$readproc(0x48) == $i2c_addr;
3210  for ($i = 0x2b; $i <= 0x3d; $i ++) {
3211    return 0 unless &$readproc($i) == i2c_smbus_read_byte_data($file,$i);
3212  }
3213  return 1;
3214}
3215
3216# $_[0]: Chip to detect (0 = W83781D, 1 = W83782D, 3 = W83627HF, 5 = W83697HF)
3217#        (W83783S and AS99127F not on ISA bus)
3218# $_[1]: Address
3219# Returns: undef if not detected, (8) if detected.
3220sub w83781d_isa_detect
3221{
3222  my ($chip,$addr) = @_ ;
3223  my ($reg1,$reg2);
3224  my $val = inb ($addr + 1);
3225  return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or
3226            inb ($addr + 7) != $val;
3227
3228  $val = inb($addr + 5) & 0x7f;
3229  outb($addr+5, ~$val & 0xff);
3230  if ((inb ($addr+5) & 0x7f) != (~ $val & 0x7f)) {
3231    outb($addr+5,$val);
3232    return;
3233  }
3234
3235  my $read_proc = sub { isa_read_byte $addr + 5, $addr + 6, @_ };
3236  $reg1 = &$read_proc(0x4e);
3237  $reg2 = &$read_proc(0x4f);
3238  return unless (($reg1 & 0x80) == 0x00 and $reg2 == 0xa3) or 
3239                (($reg1 & 0x80) == 0x80 and $reg2 == 0x5c);
3240  return unless ($reg1 & 0x07) == 0x00;
3241  $reg1 = &$read_proc(0x58) & 0xfe;
3242  return if $chip == 0 and  $reg1 != 0x10;
3243  return if $chip == 1 and  $reg1 != 0x30;
3244  return if $chip == 3 and  $reg1 != 0x20;
3245  return if $chip == 5 and  $reg1 != 0x60;
3246  return 8;
3247}
3248
3249# $_[0]: Chip to detect (0 = Revision 0x00, 1 = Revision 0x80)
3250# $_[1]: A reference to the file descriptor to access this chip.
3251#        We may assume an i2c_set_slave_addr was already done.
3252# $_[2]: Address
3253# Returns: undef if not detected, (6) if detected.
3254# Registers used:
3255#   0x00: Device ID
3256#   0x01: Revision ID
3257#   0x03: Configuration
3258# Mediocre detection
3259sub gl518sm_detect
3260{
3261  my $reg;
3262  my ($chip,$file,$addr) = @_;
3263  return unless i2c_smbus_read_byte_data($file,0x00) == 0x80;
3264  return unless (i2c_smbus_read_byte_data($file,0x03) & 0x80) == 0x00;
3265  $reg = i2c_smbus_read_byte_data($file,0x01);
3266  return unless ($chip == 0 and $reg == 0x00) or
3267                ($chip == 1 and $reg == 0x80);
3268  return (6);
3269}
3270
3271# $_[0]: A reference to the file descriptor to access this chip.
3272#        We may assume an i2c_set_slave_addr was already done.
3273# $_[1]: Address
3274# Returns: undef if not detected, (5) if detected.
3275# Registers used:
3276#   0x00: Device ID
3277#   0x01: Revision ID
3278#   0x03: Configuration
3279# Mediocre detection
3280sub gl520sm_detect
3281{
3282  my ($file,$addr) = @_;
3283  return unless i2c_smbus_read_byte_data($file,0x00) == 0x20;
3284  return unless (i2c_smbus_read_byte_data($file,0x03) & 0x80) == 0x00;
3285  # The line below must be better checked before I dare to use it.
3286  # return unless i2c_smbus_read_byte_data($file,0x01) == 0x00;
3287  return (5);
3288}
3289
3290# $_[0]: A reference to the file descriptor to access this chip.
3291#        We may assume an i2c_set_slave_addr was already done.
3292# $_[1]: Address
3293# Returns: undef if not detected, (5) if detected.
3294# Registers used:
3295#   0x00: Device ID
3296# Mediocre detection
3297sub gl525sm_detect
3298{
3299  my ($file,$addr) = @_;
3300  return unless i2c_smbus_read_byte_data($file,0x00) == 0x25;
3301  return (5);
3302}
3303
3304# $_[0]: Chip to detect (0 = ADM9240, 1 = DS1780, 2 = LM81)
3305# $_[1]: A reference to the file descriptor to access this chip.
3306#        We may assume an i2c_set_slave_addr was already done.
3307# $_[2]: Address
3308# Returns: undef if not detected, (7) if detected.
3309# Registers used:
3310#   0x3e: Company ID
3311#   0x40: Configuration
3312#   0x48: Full I2C Address
3313# Note: Detection overrules a previous LM78 detection
3314sub adm9240_detect
3315{
3316  my $reg;
3317  my ($chip, $file,$addr) = @_;
3318  $reg = i2c_smbus_read_byte_data($file,0x3e);
3319  return unless ($chip == 0 and $reg == 0x23) or
3320                ($chip == 1 and $reg == 0xda) or
3321                ($chip == 2 and $reg == 0x01);
3322  return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
3323  return unless i2c_smbus_read_byte_data($file,0x48) == $addr;
3324 
3325  return (7);
3326}
3327
3328# $_[0]: Chip to detect (0 = ADM1022, 1 = THMC50, 2 = ADM1028)
3329# $_[1]: A reference to the file descriptor to access this chip.
3330#        We may assume an i2c_set_slave_addr was already done.
3331# $_[2]: Address
3332# Returns: undef if not detected, (8) if detected.
3333# Registers used:
3334#   0x3e: Company ID
3335#   0x3f: Revision
3336#   0x40: Configuration
3337# Note: Detection overrules a previous LM78 or ADM9240 detection
3338sub adm1022_detect
3339{
3340  my $reg;
3341  my ($chip, $file,$addr) = @_;
3342  $reg = i2c_smbus_read_byte_data($file,0x3e);
3343  return unless ($chip == 0 and $reg == 0x41) or
3344                ($chip == 1 and $reg == 0x49) or
3345                ($chip == 2 and $reg == 0x41);
3346  return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
3347  $reg = i2c_smbus_read_byte_data($file, 0x3f);
3348  return unless ($reg & 0xc0) == 0xc0;
3349  return if $chip == 0 and ($reg & 0xc0) != 0xc0;
3350  return if $chip == 2 and ($reg & 0xc0) == 0xc0;
3351  return (8);
3352}
3353
3354# $_[0]: Chip to detect (0 = ADM1025, 1 = NE1619)
3355# $_[1]: A reference to the file descriptor to access this chip.
3356#        We may assume an i2c_set_slave_addr was already done.
3357# $_[2]: Address
3358# Returns: undef if not detected, (8) if detected.
3359# Registers used:
3360#   0x3e: Company ID
3361#   0x3f: Revision
3362#   0x40: Configuration
3363# Note: Detection overrules a previous LM78 or ADM9240 detection
3364sub adm1025_detect
3365{
3366  my $reg;
3367  my ($chip, $file,$addr) = @_;
3368
3369  $reg = i2c_smbus_read_byte_data($file,0x3e);
3370  return if ($chip == 0) and ($reg != 0x41);
3371  return if ($chip == 1) and ($reg != 0xA1);
3372
3373  return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
3374  return unless (i2c_smbus_read_byte_data($file,0x3f) & 0xf0) == 0x20;
3375
3376  return (8);
3377}
3378
3379# $_[0]: Chip to detect (0 = ADM1026)
3380# $_[1]: A reference to the file descriptor to access this chip.
3381#        We may assume an i2c_set_slave_addr was already done.
3382# $_[2]: Address
3383# Returns: undef if not detected, (8) if detected.
3384# Registers used:
3385#   0x16: Company ID
3386#   0x17: Revision
3387sub adm1026_detect
3388{
3389  my $reg;
3390  my ($chip, $file,$addr) = @_;
3391  $reg = i2c_smbus_read_byte_data($file,0x16);
3392  return unless ($reg == 0x41);
3393  return unless (i2c_smbus_read_byte_data($file,0x17) & 0xf0) == 0x40;
3394  return (8);
3395}
3396
3397# $_[0]: Chip to detect (0 = ADM1024)
3398# $_[1]: A reference to the file descriptor to access this chip.
3399#        We may assume an i2c_set_slave_addr was already done.
3400# $_[2]: Address
3401# Returns: undef if not detected, (8) if detected.
3402# Registers used:
3403#   0x3e: Company ID
3404#   0x3f: Revision
3405#   0x40: Configuration
3406sub adm1024_detect
3407{
3408  my $reg;
3409  my ($chip, $file,$addr) = @_;
3410  $reg = i2c_smbus_read_byte_data($file,0x3e);
3411  return unless ($reg == 0x41);
3412  return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
3413  return unless (i2c_smbus_read_byte_data($file,0x3f) & 0xf0) == 0x10;
3414  return (8);
3415}
3416
3417# $_[0]: Chip to detect
3418#   (0 = ADM1021, 1 = ADM1021A/ADM1023, 2 = MAX1617, 3 = MAX1617A, 4 = THMC10,
3419#    5 = LM84, 6 = GL523, 7 = MC1066)
3420# $_[1]: A reference to the file descriptor to access this chip.
3421#        We may assume an i2c_set_slave_addr was already done.
3422# $_[2]: Address
3423# Returns: undef if not detected, 3 if simply detected, 5 if detected and
3424#          manufacturer ID matches, 7 if detected and manufacturer ID and
3425#          revision match
3426# Registers used:
3427#   0x04: Company ID (LM84 only)
3428#   0xfe: Company ID (all but LM84 and MAX1617)
3429#   0xff: Revision (ADM1021, ADM1021A/ADM1023 and MAX1617A)
3430#   0x02: Status
3431#   0x03: Configuration
3432#   0x04: Conversion rate
3433#   0x00-0x01, 0x05-0x08: Temperatures (MAX1617 and LM84)
3434# Note: Especially the MAX1617 has very bad detection; we give it a low
3435# confidence value.
3436sub adm1021_detect
3437{
3438  my ($chip, $file, $addr) = @_;
3439  my $man_id = i2c_smbus_read_byte_data($file, 0xfe);
3440  my $rev = i2c_smbus_read_byte_data($file, 0xff);
3441  my $conf = i2c_smbus_read_byte_data($file, 0x03);
3442  my $status = i2c_smbus_read_byte_data($file, 0x02);
3443  my $convrate = i2c_smbus_read_byte_data($file, 0x04);
3444
3445  # Check manufacturer IDs and product revisions when available
3446  return if $chip == 0 and $man_id != 0x41 ||
3447                          ($rev & 0xf0) != 0x00;
3448  return if $chip == 1 and $man_id != 0x41 ||
3449                          ($rev & 0xf0) != 0x30;
3450  return if $chip == 3 and $man_id != 0x4d ||
3451                           $rev != 0x01;
3452  return if $chip == 4 and $man_id != 0x49;
3453  return if $chip == 5 and $convrate != 0x00;
3454  return if $chip == 6 and $man_id != 0x23;
3455  return if $chip == 7 and $man_id != 0x54;
3456
3457  # Check unused bits
3458  if ($chip == 5) # LM84
3459  {
3460    return if ($status & 0xab) != 0;
3461    return if ($conf & 0x7f) != 0;
3462  }
3463  else
3464  {
3465    return if ($status & 0x03) != 0;
3466    return if ($conf & 0x3f) != 0;
3467    return if ($convrate & 0xf8) != 0;
3468  }
3469
3470  # Extra checks for MAX1617 and LM84, since those are often misdetected
3471  # We verify several assertions (6 for the MAX1617, 4 for the LM84) and
3472  # discard the chip if any fail. Note that these checks are not done
3473  # by the adm1021 driver.
3474  if ($chip == 2 || $chip == 5)
3475  {
3476    my $lte = i2c_smbus_read_byte_data($file, 0x00);
3477    my $rte = i2c_smbus_read_byte_data($file, 0x01);
3478    my $lhi = i2c_smbus_read_byte_data($file, 0x05);
3479    my $rhi = i2c_smbus_read_byte_data($file, 0x07);
3480    my $llo = i2c_smbus_read_byte_data($file, 0x06);
3481    my $rlo = i2c_smbus_read_byte_data($file, 0x08);
3482
3483    # If all registers hold the same value, it has to be a misdetection
3484    return if $lte == $rte and $lte == $lhi and $lte == $rhi
3485           and $lte == $llo and $lte == $rlo;
3486
3487    # Negative temperatures
3488    return if ($lte & 0x80) or ($rte & 0x80);
3489    # Negative high limits
3490    return if ($lhi & 0x80) or ($rhi & 0x80);
3491    # Low limits over high limits
3492    if ($chip != 5) # LM84 doesn't have low limits
3493    {
3494      $llo-=256 if ($llo & 0x80);
3495      $rlo-=256 if ($rlo & 0x80);
3496      return if ($llo > $lhi) or ($rlo > $rhi);
3497    }
3498  }
3499
3500  return 3 if ($chip == 2) or ($chip == 5);
3501  return 7 if $chip <= 3;
3502  return 5;
3503}
3504
3505# $_[0]: Address
3506# Returns: undef if not detected, (9) if detected.
3507# Note: It is already 99% certain this chip exists if we find the PCI
3508# entry. The exact address is encoded in PCI space.
3509sub sis5595_isa_detect
3510{
3511  my ($addr) = @_;
3512  my ($key,$adapter,$try,$local_try);
3513  my $found = 0;
3514  foreach $local_try (@pci_adapters) {
3515    if ($local_try->{procid} eq "Silicon Integrated Systems SIS5595") {
3516      $try = $local_try;
3517      $found = 1;
3518      last;
3519    }
3520  }
3521  return if not $found;
3522
3523  $found = 0;
3524  while ( ($key, $adapter) = each %pci_list) {
3525    if ((defined($adapter->{vendid}) and 
3526         $try->{vendid} == $adapter->{vendid} and
3527         $try->{devid} == $adapter->{devid} and
3528         $try->{func} == $adapter->{func}) or
3529        (! defined($adapter->{vendid}) and
3530         $adapter->{desc} =~ /$try->{procid}/ and
3531         $try->{func} == $adapter->{func})) {
3532      $found = 1;
3533      last;
3534    }
3535  }
3536  return if not $found;
3537
3538  return 9;
3539}
3540
3541# $_[0]: Address
3542# Returns: undef if not detected, (9) if detected.
3543# Note: It is already 99% certain this chip exists if we find the PCI
3544# entry. The exact address is encoded in PCI space.
3545sub via686a_isa_detect
3546{
3547  my ($addr) = @_;
3548  my ($key,$adapter,$try,$local_try);
3549  my $found = 0;
3550  foreach $local_try (@pci_adapters) {
3551    if ($local_try->{procid} eq "VIA Technologies VT82C686 Apollo ACPI") {
3552      $try = $local_try;
3553      $found = 1;
3554      last;
3555    }
3556  }
3557  return if not $found;
3558
3559  $found = 0;
3560  while ( ($key, $adapter) = each %pci_list) {
3561    if ((defined($adapter->{vendid}) and 
3562         $try->{vendid} == $adapter->{vendid} and
3563         $try->{devid} == $adapter->{devid} and
3564         $try->{func} == $adapter->{func}) or
3565        (! defined($adapter->{vendid}) and
3566         $adapter->{desc} =~ /$try->{procid}/ and
3567         $try->{func} == $adapter->{func})) {
3568      $found = 1;
3569      last;
3570    }
3571  }
3572  return if not $found;
3573
3574  return 9;
3575}
3576
3577# $_[0]: Address
3578# Returns: undef if not detected, (9) if detected.
3579# Note: It is already 99% certain this chip exists if we find the PCI
3580# entry. The exact address is encoded in PCI space.
3581sub via8231_isa_detect
3582{
3583  my ($addr) = @_;
3584  my ($key,$adapter,$try,$local_try);
3585  my $found = 0;
3586  foreach $local_try (@pci_adapters) {
3587    if ($local_try->{procid} eq "VIA Technologies VT8231 South Bridge") {
3588      $try = $local_try;
3589      $found = 1;
3590      last;
3591    }
3592  }
3593  return if not $found;
3594
3595  $found = 0;
3596  while ( ($key, $adapter) = each %pci_list) {
3597    if ((defined($adapter->{vendid}) and 
3598         $try->{vendid} == $adapter->{vendid} and
3599         $try->{devid} == $adapter->{devid} and
3600         $try->{func} == $adapter->{func}) or
3601        (! defined($adapter->{vendid}) and
3602         $adapter->{desc} =~ /$try->{procid}/ and
3603         $try->{func} == $adapter->{func})) {
3604      $found = 1;
3605      last;
3606    }
3607  }
3608  return if not $found;
3609
3610  return 9;
3611}
3612
3613# $_[0]: Chip to detect (0 = ..., 1 = ...)
3614# $_[1]: A reference to the file descriptor to access this chip.
3615#        We may assume an i2c_set_slave_addr was already done.
3616# $_[2]: Address
3617# Returns: undef if not detected, 8 if detected (tops LM78).
3618# Registers used:
3619#   0x00: Configuration
3620#   0x48: Full I2C Address
3621#   0x58: Mfr ID
3622# Note that this function is always called through a closure, so the
3623# arguments are shifted by one place.
3624sub ite_detect
3625{
3626  my $reg;
3627  my ($chip,$file,$addr) = @_;
3628  return unless i2c_smbus_read_byte_data($file,0x48) == $addr;
3629  return unless (i2c_smbus_read_byte_data($file,0x00) & 0x80) == 0x00;
3630  return unless i2c_smbus_read_byte_data($file,0x58) == 0x90;
3631  return (8);
3632}
3633
3634# $_[0]: Chip to detect (0 = ..., 1 = ...)
3635# $_[1]: Address
3636# Returns: undef if not detected, 8 if detected (tops LM78).
3637# Note: Only address 0x290 is scanned at this moment.
3638sub ite_isa_detect
3639{
3640  my ($chip,$addr) = @_ ;
3641  my $val = inb ($addr + 1);
3642  return if inb ($addr + 2) != $val or inb ($addr + 3) != $val or 
3643            inb ($addr + 7) != $val;
3644
3645  $val = inb($addr + 5) & 0x7f;
3646  outb($addr+5, ~$val & 0xff);
3647  if ((inb ($addr+5) & 0x7f) != (~ $val & 0x7f)) {
3648    outb($addr+5,$val);
3649    return;
3650  }
3651  my $readproc = sub { isa_read_byte $addr + 5, $addr + 6, @_ };
3652  return unless (&$readproc(0x00) & 0x80) == 0x00;
3653  my $reg = &$readproc(0x58);
3654  return unless ($reg == 0x90);
3655  return 8;
3656}
3657
3658
3659# $_[0]: Chip to detect (0 = ..., 1 = ...)
3660# $_[1]: ISA address
3661# $_[2]: I2C file handle
3662# $_[3]: I2C address
3663sub ite_alias_detect
3664{
3665  my ($chip,$isa_addr,$file,$i2c_addr) = @_;
3666  my $i;
3667  my $readproc = sub { isa_read_byte $isa_addr + 5, $isa_addr + 6, @_ };
3668  return 0 unless &$readproc(0x48) == $i2c_addr;
3669  for ($i = 0x2b; $i <= 0x3d; $i ++) {
3670    return 0 unless &$readproc($i) == i2c_smbus_read_byte_data($file,$i);
3671  }
3672  return 1;
3673}
3674
3675# $_[0]: Chip to detect (0 = SPD EEPROM, 1 = Sony Vaio EEPROM)
3676# $_[1]: A reference to the file descriptor to access this chip
3677# $_[2]: Address
3678# Returns: 8 for a memory eeprom, 4 to 9 for a Sony Vaio eeprom,
3679#          1 for an unknown eeprom
3680# Registers used:
3681#   0-63: SPD Data and Checksum
3682#   0x80-0x83: Sony Vaio Data ("PCG-")
3683#   0xe2, 0xe5, 0xe8, 0xeb, Oxee: Sony Vaio Timestamp constant bytes.
3684#   0x1a-0x1c: Sony Vaio MAC address
3685# This detection function is a bit tricky; this is to workaround
3686# wrong misdetection messages that would else arise.
3687sub eeprom_detect
3688{
3689  my ($chip,$file,$addr) = @_;
3690
3691  # Check the checksum for validity (works for most DIMMs and RIMMs)
3692  my $checksum = 0;
3693  for (my $i = 0; $i <= 62; $i ++) {
3694    $checksum += i2c_smbus_read_byte_data($file,$i);
3695  }
3696  $checksum &= 255;
3697  return 8
3698    if $chip == 0 and i2c_smbus_read_byte_data($file,63) == $checksum;
3699
3700  # Look for a Sony Vaio EEPROM
3701  my $vaioconf = 1;
3702  $vaioconf += 4
3703    if i2c_smbus_read_byte_data($file,0x80) == 0x50
3704    && i2c_smbus_read_byte_data($file,0x81) == 0x43
3705    && i2c_smbus_read_byte_data($file,0x82) == 0x47
3706    && i2c_smbus_read_byte_data($file,0x83) == 0x2d;
3707  $vaioconf += 5
3708    if i2c_smbus_read_byte_data($file,0xe2) == 0x2f
3709    && i2c_smbus_read_byte_data($file,0xe5) == 0x2f
3710    && i2c_smbus_read_byte_data($file,0xe8) == 0x20
3711    && i2c_smbus_read_byte_data($file,0xeb) == 0x3a
3712    && i2c_smbus_read_byte_data($file,0xee) == 0x3a;
3713  $vaioconf += 3
3714    if i2c_smbus_read_byte_data($file,0x1a) == 0x08
3715    && i2c_smbus_read_byte_data($file,0x1b) == 0x00
3716    && i2c_smbus_read_byte_data($file,0x1c) == 0x46;
3717  $vaioconf = 9
3718    if $vaioconf > 9;
3719
3720  if ($vaioconf > 1) {
3721    return if $chip != 1;
3722    return $vaioconf;
3723  }
3724
3725  # Even if all tests fail, it still may be an eeprom
3726  return if $chip != 0;
3727  # Default to SPD EEPROM
3728  return 1;
3729}
3730
3731# $_[0]: A reference to the file descriptor to access this chip.
3732#        We may assume an i2c_set_slave_addr was already done.
3733# $_[1]: Address
3734# Returns: undef if not detected, (1) if detected.
3735# Detection is impossible!
3736sub ltc1710_detect
3737{
3738  return (1);
3739}
3740
3741# $_[0]: A reference to the file descriptor to access this chip.
3742#        We may assume an i2c_set_slave_addr was already done.
3743# $_[1]: Address
3744# Returns: undef if not detected, (1) if detected.
3745# Registers used:
3746#   0x00..0x07: DDC signature
3747#   0x08..0x7E: checksumed area
3748#   0x7F:       checksum
3749### commented out additional location checks for now - don't work?
3750sub ddcmonitor_detect
3751{
3752  my ($file,$addr) = @_;
3753  my $i;
3754###  for ($i = 0; $i < 8; $i ++) {
3755###    i2c_set_slave_addr \*FILE,$addr+$i or goto FAILURE;
3756    i2c_smbus_read_byte_data($file,0x00) == 0x00 or goto FAILURE;
3757    i2c_smbus_read_byte_data($file,0x01) == 0xFF or goto FAILURE;
3758    i2c_smbus_read_byte_data($file,0x02) == 0xFF or goto FAILURE;
3759    i2c_smbus_read_byte_data($file,0x03) == 0xFF or goto FAILURE;
3760    i2c_smbus_read_byte_data($file,0x04) == 0xFF or goto FAILURE;
3761    i2c_smbus_read_byte_data($file,0x05) == 0xFF or goto FAILURE;
3762    i2c_smbus_read_byte_data($file,0x06) == 0xFF or goto FAILURE;
3763    i2c_smbus_read_byte_data($file,0x07) == 0x00 or goto FAILURE;
3764###  }
3765###  i2c_set_slave_addr \*FILE,$addr or return;
3766  # Check the checksum for validity. We should do this for all addresses,
3767  # but it would be too slow.
3768  my $checksum = 0;
3769  for ($i = 0; $i <= 127; $i = $i + 1) {
3770    $checksum = $checksum + i2c_smbus_read_byte_data($file,$i);
3771  }
3772  $checksum=$checksum & 255;
3773  if ($checksum != 0) {
3774    # I have one such monitor...
3775    return (2,$addr+1,$addr+2,$addr+3,$addr+4,$addr+5,$addr+6,$addr+7);
3776  }
3777  return (8,$addr+1,$addr+2,$addr+3,$addr+4,$addr+5,$addr+6,$addr+7);
3778FAILURE:
3779  i2c_set_slave_addr \*FILE,$addr;
3780  return;
3781}
3782
3783# $_[0]: A reference to the file descriptor to access this chip.
3784#        We may assume an i2c_set_slave_addr was already done.
3785# $_[1]: Address
3786# Returns: undef if not detected, (8) if detected.
3787# Registers used:
3788#   0x00-0x02: Identification ('P','E','G' -> Pegasus ? :-)
3789sub fscpos_detect
3790{
3791  my ($file,$addr) = @_;
3792  # check the first 3 registers
3793  if (i2c_smbus_read_byte_data($file,0x00) != 0x50) {
3794        return;
3795  }
3796  if (i2c_smbus_read_byte_data($file,0x01) != 0x45) {
3797        return;
3798  }
3799  if (i2c_smbus_read_byte_data($file,0x02) != 0x47) {
3800        return;
3801  }
3802  return (8);
3803}
3804
3805# $_[0]: A reference to the file descriptor to access this chip.
3806#        We may assume an i2c_set_slave_addr was already done.
3807# $_[1]: Address
3808# Returns: undef if not detected, (8) if detected.
3809# Registers used:
3810#   0x00-0x02: Identification ('S','C','Y')
3811sub fscscy_detect
3812{
3813  my ($file,$addr) = @_;
3814  # check the first 3 registers
3815  if (i2c_smbus_read_byte_data($file,0x00) != 0x53) {
3816        return;
3817  }
3818  if (i2c_smbus_read_byte_data($file,0x01) != 0x43) {
3819        return;
3820  }
3821  if (i2c_smbus_read_byte_data($file,0x02) != 0x59) {
3822        return;
3823  }
3824  return (8);
3825}
3826
3827# $_[0]: A reference to the file descriptor to access this chip.
3828#        We may assume an i2c_set_slave_addr was already done.
3829# $_[1]: Address
3830# Returns: undef if not detected, (8) if detected.
3831# Registers used:
3832#   0x00-0x02: Identification ('H','E','R')
3833sub fscher_detect
3834{
3835  my ($file,$addr) = @_;
3836  # check the first 3 registers
3837  if (i2c_smbus_read_byte_data($file,0x00) != 0x48) {
3838        return;
3839  }
3840  if (i2c_smbus_read_byte_data($file,0x01) != 0x45) {
3841        return;
3842  }
3843  if (i2c_smbus_read_byte_data($file,0x02) != 0x52) {
3844        return;
3845  }
3846  return (8);
3847}
3848
3849# $_[0]: A reference to the file descriptor to access this chip.
3850#        We may assume an i2c_set_slave_addr was already done.
3851# $_[1]: Address
3852# Returns: undef if not detected, (7) if detected.
3853# Registers used:
3854#   0x3F: Revision ID
3855#   0x48: Address
3856#   0x4A, 0x4B, 0x4F, 0x57, 0x58: Reserved bits.
3857# We do not use 0x49's reserved bits on purpose. The register is named
3858# "VID4/Device ID" so it is doubtful bits 7-1 are really unused.
3859sub m5879_detect
3860{
3861  my ($file, $addr) = @_;
3862
3863  return
3864    unless i2c_smbus_read_byte_data($file, 0x3F) == 0x01;
3865 
3866  return
3867    unless i2c_smbus_read_byte_data($file, 0x48) == $addr;
3868 
3869  return
3870    unless (i2c_smbus_read_byte_data($file, 0x4A) & 0x06) == 0
3871       and (i2c_smbus_read_byte_data($file, 0x4B) & 0xFC) == 0
3872       and (i2c_smbus_read_byte_data($file, 0x4F) & 0xFC) == 0
3873       and (i2c_smbus_read_byte_data($file, 0x57) & 0xFE) == 0
3874       and (i2c_smbus_read_byte_data($file, 0x58) & 0xEF) == 0;
3875
3876  return (7);
3877}
3878
3879# $_[0]: A reference to the file descriptor to access this chip.
3880#        We may assume an i2c_set_slave_addr was already done.
3881# $_[1]: Address
3882# Returns: undef if not detected, 4 or 7 if detected
3883# Detection is based on the fact that the SAA1064 has only one readable
3884# register, and thus ignores the read address. This register can have value
3885# 0x80 (first read since power-up) or 0x00.
3886sub saa1064_detect
3887{
3888        my ($file,$addr) = @_;
3889        my $status = i2c_smbus_read_byte_data ($file, 0x00);
3890
3891        return if ($status & 0x7f) != 0x00;
3892
3893        for (my $i=0 ; $i<256; $i++) {
3894                return if i2c_smbus_read_byte_data ($file, $i) != 0x00;
3895        }
3896
3897        return 7
3898                if $status == 0x80;
3899        return 4;
3900}
3901
3902# $_[0]: A reference to the file descriptor to access this chip.
3903#        We may assume an i2c_set_slave_addr was already done.
3904# $_[1]: Address
3905# Returns: undef if not detected, 1 if detected
3906# Detection is rather difficult, since the PCA9540 has a single register.
3907# Fortunately, no other device is known to live at this address.
3908sub pca9540_detect
3909{
3910        my ($file, $addr) = @_;
3911        my $reg = i2c_smbus_read_byte($file);
3912
3913        return if ($reg & 0xf7);
3914        return if $reg != i2c_smbus_read_byte($file);
3915        return if $reg != i2c_smbus_read_byte($file);
3916        return if $reg != i2c_smbus_read_byte($file);
3917
3918        return 1;
3919}
3920
3921# $_[0]: A reference to the file descriptor to access this chip.
3922#        We may assume an i2c_set_slave_addr was already done.
3923# $_[1]: Address
3924# Returns: undef if not detected, 3 if detected
3925sub max6900_detect
3926{
3927        my ($file,$addr) = @_;
3928        my $reg;
3929       
3930        # SEC
3931        $reg = i2c_smbus_read_byte_data ($file, 0x81);
3932        return if
3933                ($reg & 0xF0) > 0x50 or
3934                ($reg & 0x0F) > 9;
3935
3936        # MIN
3937        $reg = i2c_smbus_read_byte_data ($file, 0x83);
3938        return if
3939                ($reg & 0xF0) > 0x50 or
3940                ($reg & 0x0F) > 9;
3941
3942        # HR
3943        $reg = i2c_smbus_read_byte_data ($file, 0x85);
3944        return if
3945                ($reg & 0x40) != 0x00 or
3946                ($reg & 0x0F) > 9;
3947
3948        # DATE
3949        $reg = i2c_smbus_read_byte_data ($file, 0x87);
3950        return if
3951                $reg == 0x00 or
3952                ($reg & 0xF0) > 0x30 or
3953                ($reg & 0x0F) > 9;
3954
3955        # MONTH
3956        $reg = i2c_smbus_read_byte_data ($file, 0x89);
3957        return if
3958                $reg == 0x00 or
3959                ($reg & 0xF0) > 0x10 or
3960                ($reg & 0x0F) > 9;
3961
3962        # DAY
3963        $reg = i2c_smbus_read_byte_data ($file, 0x8B);
3964        return if
3965                $reg == 0 or
3966                $reg > 7;
3967
3968        # YEAR
3969        $reg = i2c_smbus_read_byte_data ($file, 0x8D);
3970        return if
3971                ($reg & 0xF0) > 0x90 or
3972                ($reg & 0x0F) > 9;
3973
3974        # CONTROL
3975        $reg = i2c_smbus_read_byte_data ($file, 0x8F);
3976        return if
3977                ($reg & 0x7F) != 0x00;
3978
3979        # CENTURY
3980        $reg = i2c_smbus_read_byte_data ($file, 0x93);
3981        return if
3982                ($reg & 0xF0) > 0x90 or
3983                ($reg & 0x0F) > 9;
3984
3985        return 3;
3986}
3987
3988# $_[0]: A reference to the file descriptor to access this chip.
3989#        We may assume an i2c_set_slave_addr was already done.
3990# $_[1]: Address
3991# Returns: 1
3992# This is a placeholder so we get a report if any device responds
3993# to the SMBus Device Default Address (0x61), which is used for
3994# ARP in SMBus 2.0.
3995sub arp_detect
3996{
3997  return (1);
3998}
3999
4000# This checks for non-FFFF values for SpecInfo and Status.
4001# The address (0x09) is specified by the SMBus standard so it's likely
4002# that this really is a smart battery charger.
4003# $_[0]: A reference to the file descriptor to access this chip.
4004#        We may assume an i2c_set_slave_addr was already done.
4005# $_[1]: Address
4006# Returns: 5
4007sub smartbatt_chgr_detect
4008{
4009  my ($file,$addr) = @_;
4010  # check some registers
4011  if (i2c_smbus_read_word_data($file,0x11) == 0xffff) {
4012        return;
4013  }
4014  if (i2c_smbus_read_word_data($file,0x13) == 0xffff) {
4015        return;
4016  }
4017  return (5);
4018}
4019
4020# This checks for non-FFFF values for State and Info.
4021# The address (0x0a) is specified by the SMBus standard so it's likely
4022# that this really is a smart battery manager/selector.
4023# $_[0]: A reference to the file descriptor to access this chip.
4024#        We may assume an i2c_set_slave_addr was already done.
4025# $_[1]: Address
4026# Returns: 5
4027sub smartbatt_mgr_detect
4028{
4029  my ($file,$addr) = @_;
4030  # check some registers
4031  if (i2c_smbus_read_word_data($file,0x01) == 0xffff) {
4032        return;
4033  }
4034  if (i2c_smbus_read_word_data($file,0x04) == 0xffff) {
4035        return;
4036  }
4037  return (5);
4038}
4039
4040# This checks for non-FFFF values for temperature, voltage, and current.
4041# The address (0x0b) is specified by the SMBus standard so it's likely
4042# that this really is a smart battery.
4043# $_[0]: A reference to the file descriptor to access this chip.
4044#        We may assume an i2c_set_slave_addr was already done.
4045# $_[1]: Address
4046# Returns: 5
4047sub smartbatt_detect
4048{
4049  my ($file,$addr) = @_;
4050  # check some registers
4051  if (i2c_smbus_read_word_data($file,0x08) == 0xffff) {
4052        return;
4053  }
4054  if (i2c_smbus_read_word_data($file,0x09) == 0xffff) {
4055        return;
4056  }
4057  if (i2c_smbus_read_word_data($file,0x0a) == 0xffff) {
4058        return;
4059  }
4060  return (5);
4061}
4062
4063# Returns: 4
4064# These are simple detectors that only look for a register at the
4065# standard location. No writes are performed.
4066# For KCS, use the STATUS register. For SMIC, use the FLAGS register.
4067sub ipmi_kcs_detect
4068{
4069  return if inb (0x0ca3) == 0xff;
4070  return (4);
4071}
4072
4073sub ipmi_smic_detect
4074{
4075  return if inb (0x0cab) == 0xff;
4076  return (4);
4077}
4078
4079# $_[0]: Chip to detect (0 = W83L784R/AR, 1 = W83L785R)
4080# $_[1]: A reference to the file descriptor to access this chip.
4081# $_[2]: Address
4082# Returns: undef if not detected, 6 or 8 if detected
4083# Registers used:
4084#   0x40: Configuration
4085#   0x4a: Full I2C Address (not W83L785R)
4086#   0x4b: I2C addresses of emulated LM75 chips (not W83L785R)
4087#   0x4c: Winbond Vendor ID (Low Byte)
4088#   0x4d: Winbond Vendor ID (High Byte)
4089#   0x4e: Chip ID
4090# Note that this function is always called through a closure, so the
4091# arguments are shifted by one place.
4092sub w83l784r_detect
4093{
4094  my ($reg,@res);
4095  my ($chip,$file,$addr) = @_;
4096
4097  return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
4098  return if $chip == 0
4099    and i2c_smbus_read_byte_data($file,0x4a) != $addr;
4100  return unless i2c_smbus_read_byte_data($file,0x4c) == 0xa3;
4101  return unless i2c_smbus_read_byte_data($file,0x4d) == 0x5c;
4102  return if $chip == 0
4103    and i2c_smbus_read_byte_data($file,0x4e) != 0x50;
4104  return if $chip == 1
4105    and i2c_smbus_read_byte_data($file,0x4e) != 0x60;
4106
4107  $reg = i2c_smbus_read_byte_data($file,0x4b);
4108
4109  return 6 if $chip == 1; # W83L785R doesn't have subclients
4110 
4111  @res = (8);
4112  push @res, ($reg & 0x07) + 0x48 unless $reg & 0x08 ;
4113  push @res, (($reg & 0x70) >> 4) + 0x48 unless $reg & 0x80;
4114  return @res;
4115}
4116
4117# $_[0]: Chip to detect (0 = W83L785TS-S)
4118# $_[1]: A reference to the file descriptor to access this chip.
4119#        We may assume an i2c_set_slave_addr was already done.
4120# $_[2]: Address
4121# Returns: undef if not detected, 8 if detected
4122# Registers used:
4123#   0x4C-4E: Mfr and Chip ID
4124# Note that this function is always called through a closure, so the
4125# arguments are shifted by one place.
4126sub w83l785ts_detect
4127{
4128  my ($chip,$file,$addr) = @_;
4129  return unless i2c_smbus_read_byte_data($file,0x4c) == 0xa3;
4130  return unless i2c_smbus_read_byte_data($file,0x4d) == 0x5c;
4131  return unless i2c_smbus_read_byte_data($file,0x4e) == 0x70;
4132  return (8);
4133}
4134
4135# $_[0]: Chip to detect. Always zero for now, but available for future use
4136#        if somebody finds a way to distinguish MAX6650 and MAX6651.
4137# $_[1]: A reference to the file descriptor to access this chip.
4138#        We may assume an i2c_set_slave_addr was already done.
4139# $_[2]: Address
4140# Returns: undef if not detected, 4 if detected.
4141#
4142# The max6650 has no device ID register. However, a few registers have
4143# spare bits, which are documented as being always zero on read. We read
4144# all of these registers check the spare bits. Any non-zero means this
4145# is not a max6650/1.
4146#
4147# The always zero bits are:
4148#   configuration byte register (0x02) - top 2 bits
4149#   gpio status register (0x14) - top 3 bits
4150#   alarm enable register (0x08) - top 3 bits
4151#   alarm status register (0x0A) - top 3 bits
4152#   tachometer count time register (0x16) - top 6 bits
4153sub max6650_detect
4154{
4155  my ($chip, $file) = @_;
4156  return if i2c_smbus_read_byte_data($file,0x16) & 0xFC;
4157  return if i2c_smbus_read_byte_data($file,0x0A) & 0xE0;
4158  return if i2c_smbus_read_byte_data($file,0x08) & 0xE0;
4159  return if i2c_smbus_read_byte_data($file,0x14) & 0xE0;
4160  return if i2c_smbus_read_byte_data($file,0x02) & 0xC0;
4161  return 4;
4162}
4163
4164
4165################
4166# MAIN PROGRAM #
4167################
4168
4169# $_[0]: reference to a list of chip hashes
4170sub print_chips_report 
4171{
4172  my ($listref) = @_;
4173  my $data;
4174 
4175  foreach $data (@$listref) {
4176    my $is_i2c = exists $data->{i2c_addr};
4177    my $is_isa = exists $data->{isa_addr};
4178    print "  * ";
4179    if ($is_i2c) {
4180      printf "Bus `%s' (%s)\n", $data->{i2c_adap}, $data->{i2c_algo};
4181      printf "    Busdriver `%s', I2C address 0x%02x", 
4182             $data->{i2c_driver}, $data->{i2c_addr};
4183      if (exists $data->{i2c_sub_addrs}) {
4184        print " (and";
4185        my $sub_addr;
4186        foreach $sub_addr (@{$data->{i2c_sub_addrs}}) {
4187          printf " 0x%02x",$sub_addr;
4188        }
4189        print ")"
4190      }
4191      print "\n";
4192    }
4193    if ($is_isa) {
4194      print "    " if  $is_i2c;
4195      if ($data->{isa_addr}) {
4196        printf "ISA bus address 0x%04x (Busdriver `i2c-isa')\n", 
4197               $data->{isa_addr};
4198      } else {
4199        printf "ISA bus, undetermined address (Busdriver `i2c-isa')\n"
4200      }
4201    }
4202    printf "    Chip `%s' (confidence: %d)\n",
4203           $data->{chipname},  $data->{conf};
4204  }
4205}
4206
4207# $_[0]: 1 if ISA bus is prefered, 0 for SMBus
4208# We build here an array adapters, indexed on the number the adapter has
4209# at this moment (we assume only loaded adapters are interesting at all;
4210# everything that got scanned also got loaded). Each entry is a reference
4211# to a hash containing:
4212#  driver: Name of the adapter driver
4213#  nr_now: Number of the bus now
4214#  nr_later: Number of the bus when the modprobes are done (not included if the
4215#        driver should not be loaded)
4216# A second array, called
4217sub generate_modprobes
4218{
4219  my ($prefer_isa) = @_;
4220
4221  my ($chip,$detection,$nr,$i,@optionlist,@probelist,$driver,$isa,$adap);
4222  my @adapters;
4223  my $modprobes = "";
4224  my $configfile = "";
4225
4226  # These are always needed
4227  $configfile .= "# I2C module options\n";
4228  $configfile .= "alias char-major-89 i2c-dev\n";
4229
4230  # Collect all loaded adapters
4231  # i2cdetect -l either cats /proc/bus/i2c or scans sysfs for the same information
4232  open INPUTFILE,"i2cdetect -l |" or die "Couldn't find i2cdetect program!!";
4233  while (<INPUTFILE>) {
4234    my ($dev_nr,$type,$adap,$algo) = /^i2c-(\S+)\s+(\S+)\s+(.*?)\s*\t\s*(.*?)\s+$/;
4235    next if ($type eq "dummy");
4236    $adapters[$dev_nr]->{driver} = find_adapter_driver($adap,$algo);
4237    $adapters[$dev_nr]->{adapname} = $adap;
4238    $adapters[$dev_nr]->{algoname} = $algo;
4239  }
4240  close INPUTFILE;
4241
4242  # Collect all adapters used
4243  $nr = 0;
4244  $isa = 0;
4245  $modprobes .= "# I2C adapter drivers\n";
4246  foreach $chip (@chips_detected) {
4247    foreach $detection (@{$chip->{detected}}) {
4248      # If there is more than one bus detected by a driver, they are
4249      # still all added. So we number them in the correct order
4250      if (exists $detection->{i2c_driver} and
4251          not exists $adapters[$detection->{i2c_devnr}]->{nr_later} and 
4252          not (exists $detection->{isa_addr} and $prefer_isa)) {
4253         foreach $adap (@adapters) {
4254           $adap->{nr_later} = $nr++ if $adap->{driver} eq $detection->{i2c_driver};
4255         }
4256      }
4257      if (exists $detection->{isa_addr} and
4258          not (exists $detection->{i2c_driver} and not $prefer_isa)) {
4259           $isa=1;
4260      }
4261    }
4262  }
4263
4264  for ($i = 0; $i < $nr; $i++) {
4265    foreach $adap (@adapters) {
4266      if ($adap->{driver} eq "UNKNOWN") {
4267        $modprobes .= "# modprobe unknown adapter ".$adap->{adapname}." using ". $adap->{algoname}."\n";
4268      } elsif ($adap->{driver} eq "DISABLED") {
4269        $modprobes .= "# modprobe disabled adapter ".$adap->{adapname}." using ". $adap->{algoname}."\n";
4270      } elsif ($adap->{driver} eq "to-be-written") {
4271        $modprobes .= "# no driver available for adapter ".$adap->{adapname}." using ". $adap->{algoname}."\n";
4272      } else {
4273        $modprobes .= "modprobe $adap->{driver}\n" if (defined($adap->{nr_later}) and $adap->{nr_later} == $i) and not $modprobes =~ /modprobe $adap->{driver}\n/;
4274      }
4275    }
4276  }
4277  $modprobes .= "modprobe i2c-isa\n" if ($isa);
4278
4279  # Now determine the chip probe lines
4280  $modprobes .= "# I2C chip drivers\n";
4281  foreach $chip (@chips_detected) {
4282    next if not @{$chip->{detected}};
4283    if ($chip->{driver} eq "to-be-written") {
4284      $modprobes .= "# no driver for $chip->{detected}[0]{chipname} yet, ask us for one!\n";
4285    } else {
4286      $modprobes .= "modprobe $chip->{driver}\n";
4287    }
4288    @optionlist = ();
4289    @probelist = ();
4290
4291    # Handle detects at addresses normally not probed
4292    foreach $detection (@{$chip->{detected}}) {
4293      push @probelist, $adapters[$detection->{i2c_devnr}]->{nr_later},
4294                       $detection->{i2c_addr}
4295           if exists $detection->{i2c_addr} and
4296              exists $detection->{i2c_extra};
4297      push @probelist, -1, $detection->{isa_addr}
4298           if exists $detection->{isa_addr} and
4299              exists $detection->{isa_extra};
4300    }
4301
4302    # Handle misdetects
4303    foreach $detection (@{$chip->{misdetected}}) {
4304      push @optionlist, $adapters[$detection->{i2c_devnr}]->{nr_later},
4305                       $detection->{i2c_addr}
4306           if exists $detection->{i2c_addr} and
4307              exists $adapters[$detection->{i2c_devnr}]->{nr_later};
4308      push @optionlist, -1, $detection->{isa_addr}
4309           if exists $detection->{isa_addr} and $isa;
4310    }
4311
4312    # Handle aliases
4313    foreach $detection (@{$chip->{detected}}) {
4314      if (exists $detection->{i2c_driver} and 
4315          exists $detection->{isa_addr} and
4316          exists $adapters[$detection->{i2c_devnr}]->{nr_later} and
4317          $isa) {
4318        if ($prefer_isa) {
4319          push @optionlist,$adapters[$detection->{i2c_devnr}]->{nr_later},
4320                           $detection->{i2c_addr};
4321        } else {
4322          push @optionlist, -1, $detection->{isa_addr}
4323        }
4324      }
4325    }
4326
4327    next if not (@probelist or @optionlist);
4328    $configfile .= "options $chip->{driver}";
4329    $configfile .= sprintf " ignore=%d,0x%02x",shift @optionlist, 
4330                                               shift @optionlist
4331                  if @optionlist;
4332    $configfile .= sprintf ",%d,0x%02x",shift @optionlist, shift @optionlist
4333                  while @optionlist;
4334    $configfile .= sprintf " probe=%d,0x%02x",shift @probelist,
4335                                              shift @probelist
4336                  if @probelist;
4337    $configfile .= sprintf ",%d,0x%02x",shift @probelist, shift @probelist
4338                  while @probelist;
4339    $configfile .= "\n";
4340  }
4341
4342  return ($modprobes,$configfile);
4343 
4344}
4345
4346# returns:
4347# 0, could not determine (can't read /dev/mem...)
4348# 1, safe system (VPD record not found)
4349# bios string (e.g. "INET32WW"), unsafe system
4350# VPD is documented here:
4351# http://www.pc.ibm.com/qtechinfo/MIGR-45120.html
4352sub vpd_bios_build_id
4353{
4354  my $pos = 0xF0000;
4355  my $found = 0;
4356  my $bbid;
4357
4358  return 0
4359    unless open MEM, '/dev/mem';
4360  binmode MEM;
4361  unless (seek MEM, $pos, SEEK_SET)
4362  {
4363    close MEM;
4364    return 0;
4365  }
4366  while ($pos <= 0xFFFD0 && !$found)
4367  {
4368    my $r = read(MEM, my $buf, 48);
4369    unless ($r == 48)
4370    {
4371      close MEM;
4372      return 0;
4373    }
4374    seek (MEM, -32, SEEK_CUR);
4375    my $len;
4376    if (substr($buf, 0, 5) eq "\xAA\x55VPD"
4377     && ord(substr($buf, 5, 1)) >= 0x30)
4378    {
4379      if (unpack('%8C*', substr($buf, 0x0D, 0x30-0x0D)) != 0)
4380      {
4381        printf " Bad VPD checksum (0x%02X)! Please report.\n",
4382                ord(substr($buf, 0x2F, 1));
4383      }
4384      $bbid = substr($buf, 13, 9);
4385      $bbid =~ s/[\x00 ]*$//; # right trim
4386      $found++;
4387    }
4388    $pos += 16;
4389  }
4390  close MEM;
4391
4392  return 1 unless $found;
4393  print " System vendor: IBM\n";
4394  print " BIOS version: $bbid\n";
4395  return "$bbid";
4396}
4397
4398# returns:
4399# 1 : the system is known to be safe
4400# 0 : the system safeness is unknown
4401# If the system is know to be unsafe (i.e. for now, IBM systems), never
4402#   return.
4403sub safe_system_vendor
4404{
4405  if ($> != 0)
4406  {
4407        print " As you are not root, we can't determine your system vendor.\n";
4408        return 0;
4409  }
4410
4411  my $vpd_bbid = vpd_bios_build_id();
4412
4413  return 0 if $vpd_bbid eq '0';
4414  return 1 if $vpd_bbid eq '1';
4415 
4416# This is where we differenciate between IBM systems (safe and unsafe).
4417# Default is to reject, white list below.
4418
4419  my %is_safe =
4420  {
4421    "2A" => 1,
4422  };
4423
4424  return 1 if defined($is_safe{substr($vpd_bbid, 0, 2)});
4425 
4426  print " Sorry, we won't let you go on. IBM systems are known to have\n",
4427        " serious problems with lm_sensors, resulting in hardware failures.\n",
4428        " For more information, see README.thinkpad or\n",
4429        " http://www2.lm-sensors.nu/~lm78/cvs/lm_sensors2/README.thinkpad.\n",
4430        " We are maintaining a \"white list\" of known-to-be-safe systems.\n",
4431        " Contact us if you know your system is safe (meaning you have actually\n",
4432        " verified it is) and want your system to be added to the list.\n\n";
4433
4434  exit;
4435}
4436
4437sub main
4438{
4439  my (@adapters,$res,$did_adapter_detection,$adapter);
4440
4441  initialize_conf;
4442  initialize_proc_pci;
4443  initialize_modules_list;
4444  initialize_kernel_version;
4445
4446  print "\nThis program will help you determine which I2C/SMBus modules you need to\n",
4447        "load to use lm_sensors most effectively. You need to have i2c and\n",
4448        "lm_sensors installed before running this program.\n";
4449  print "Also, you need to be `root', or at least have access to the $dev_i2c*\n",
4450        "files, for most things.\n";
4451  print "If you have patched your kernel and have some drivers built in, you can\n",
4452        "safely answer NO if asked to load some modules. In this case, things may\n",
4453        "seem a bit confusing, but they will still work.\n\n";
4454  print "It is generally safe and recommended to accept the default answers to all\n",
4455        "questions, unless you know what you're doing.\n\n";
4456
4457  unless (safe_system_vendor ())
4458  {
4459    print " IF THIS IS AN IBM THINKPAD, PRESS CTRL-C NOW!\n";
4460    print " IBM Thinkpads have a severely broken i2c/SMBus implementation, ";
4461    print "just scanning\n";
4462    print " the bus will break your Thinkpad forever!\n";
4463    print " If this is a non-Thinkpad IBM, we still suggest you press CTRL+C. We have\n";
4464    print " had users reporting system breakage on other IBM systems as well.\n\n";
4465  }
4466
4467  print " We can start with probing for (PCI) I2C or SMBus adapters.\n";
4468  print " You do not need any special privileges for this.\n";
4469  print " Do you want to probe now? (YES/no): ";
4470  @adapters = adapter_pci_detection
4471                        if ($did_adapter_detection = not <STDIN> =~ /\s*[Nn]/);
4472
4473  print "\n";
4474
4475  if (not $did_adapter_detection) {
4476    print "As you skipped adapter detection, we will only scan already loaded\n".
4477          "adapter modules.\n";
4478  } elsif ($> != 0) {
4479    print "As you are not root, we can't load adapter modules. We will only scan\n".
4480          "already loaded adapters.\n";
4481  } else {
4482    print "We will now try to load each adapter module in turn.\n";
4483    foreach $adapter (@adapters) {
4484      next if $adapter eq "DISABLED";
4485      if (exists($modules_list{$adapter})) {
4486        print "Module `$adapter' already loaded.\n";
4487      } else {
4488        print "Load `$adapter' (say NO if built into your kernel)? (YES/no): ";
4489        unless (<STDIN> =~ /^\s*[Nn]/) {
4490          if (system ("modprobe", $adapter)) {
4491            print "Loading failed... skipping.\n";
4492            if ($adapter eq "rivatv") {
4493              print "** Note: rivatv module is available at http://rivatv.sourceforge.net/\n"; 
4494            }
4495          } else {
4496            print "Module loaded succesfully.\n";
4497          }
4498        }
4499      }
4500    }
4501  }
4502
4503  print "If you have undetectable or unsupported adapters, you can have them\n".
4504        "scanned by manually loading the modules before running this script.\n\n";
4505
4506  print " To continue, we need module `i2c-dev' to be loaded.\n";
4507  print " If it is built-in into your kernel, you can safely skip this.\n";
4508  if (exists($modules_list{"i2c-dev"})) {
4509    print "i2c-dev is already loaded.\n";
4510  } else {
4511    if ($> != 0) {
4512      print " i2c-dev is not loaded. As you are not root, we will just hope ",
4513            "you edited\n",
4514            " `$modules_conf' for automatic loading of\n",
4515            " this module. If not, you won't be able to open any $dev_i2c* file.\n";
4516    } else {
4517      print " i2c-dev is not loaded. Do you want to load it now? (YES/no): ";
4518      if (<STDIN> =~ /^\s*[Nn]/) {
4519        print " Well, you will know best. We will just hope you edited ",
4520              "`$modules_conf'\n",
4521              " for automatic loading of this module. If not,\n",
4522              " you won't be able to open any $dev_i2c* file (unless you",
4523              "have it built-in\n",
4524              " into your kernel)\n";
4525      } elsif (system "modprobe","i2c-dev") {
4526        print " Loading failed, expect problems later on.\n";
4527      } else {
4528        print " Module loaded succesfully.\n";
4529      }
4530    }
4531  }
4532
4533  print "\n We are now going to do the adapter probings. Some adapters may ",
4534        "hang halfway\n",
4535        " through; we can't really help that. Also, some chips will be double ",
4536        "detected;\n",
4537        " we choose the one with the highest confidence value in that case.\n",
4538        " If you found that the adapter hung after probing a certain address, ",
4539        "you can\n",
4540        " specify that address to remain unprobed. That ",
4541        "often\n",
4542        " includes address 0x69 (clock chip).\n";
4543
4544  my ($inp,@not_to_scan,$inp2);
4545  # i2cdetect -l either cats /proc/bus/i2c or scans sysfs for the same information
4546  open INPUTFILE,"i2cdetect -l |" or die "Couldn't find i2cdetect program!!";
4547  while (<INPUTFILE>) {
4548    my ($dev_nr,$type,$adap,$algo) = /^i2c-(\S+)\s+(\S+)\s+(.*?)\s*\t\s*(.*?)\s+$/;
4549    next if ($type eq "dummy");
4550    print "\n";
4551    print "Next adapter: $adap ($algo)\n";
4552    print "Do you want to scan it? (YES/no/selectively): ";
4553   
4554    $inp = <STDIN>;
4555    @not_to_scan=();
4556    if ($inp =~ /^\s*[Ss]/) {
4557      print "Please enter one or more addresses not to scan. Separate them ",
4558            "with comma's.\n",
4559            "You can specify a range by using dashes. Addresses may be ",
4560            "decimal (like 54)\n",
4561            "or hexadecimal (like 0x33).\n",
4562            "Addresses: ";
4563      $inp2 = <STDIN>;
4564      chop $inp2;
4565      @not_to_scan = parse_not_to_scan 0,0x7f,$inp2;
4566    }
4567    scan_adapter $dev_nr, $adap, $algo, find_adapter_driver($adap,$algo),
4568                 \@not_to_scan   unless $inp =~ /^\s*[Nn]/;
4569  }
4570
4571  print "\nSome chips are also accessible through the ISA bus. ISA probes are\n".
4572        "typically a bit more dangerous, as we have to write to I/O ports to do\n".
4573        "this. This is usually safe though.\n\n";
4574  if ($> != 0) {
4575    print "As you are not root, we shall skip this step.\n";
4576  } else {
4577    print "Do you want to scan the ISA bus? (YES/no): ";
4578    unless (<STDIN> =~ /^\s*n/i) {
4579      initialize_ioports();
4580      scan_isa_bus();
4581      close_ioports();
4582    }
4583  }
4584
4585  print "\nSome Super I/O chips may also contain sensors. Super I/O probes are\n".
4586        "typically a bit more dangerous, as we have to write to I/O ports to do\n".
4587        "this. This is usually safe though.\n\n";
4588  if ($> != 0) {
4589    print "As you are not root, we shall skip this step.\n";
4590  } else {
4591    print "Do you want to scan for Super I/O sensors? (YES/no): ";
4592    unless (<STDIN> =~ /^\s*n/i) {
4593      initialize_ioports();
4594      scan_superio(0x2e, 0x2f);
4595      print "\nDo you want to scan for secondary Super I/O sensors? (YES/no): ";
4596      unless (<STDIN> =~ /^\s*n/i) {
4597        scan_superio(0x4e, 0x4f);
4598      }
4599      close_ioports();
4600    }
4601  }
4602
4603  if(! @chips_detected) {
4604    print "\n Sorry, no chips were detected.\n",
4605        " Either your sensors are not supported, or they are\n",
4606        " connected to an I2C bus adapter that we do not support.\n",
4607        " See doc/FAQ, doc/lm_sensors-FAQ.html, or\n",
4608        " http://www2.lm-sensors.nu/~lm78/cvs/lm_sensors2/doc/lm_sensors-FAQ.html\n",
4609        " (FAQ #4.24.3) for further information.\n",
4610        " If you find out what chips are on your board, see\n",
4611        " http://secure.netroedge.com/~lm78/newdrivers.html for driver status.\n";
4612    exit;
4613  }
4614
4615  print "\n Now follows a summary of the probes I have just done.\n";
4616  print " Just press ENTER to continue: ";
4617  <STDIN>;
4618
4619  my ($chip,$data);
4620  foreach $chip (@chips_detected) {
4621    print "\nDriver `$$chip{driver}' ";
4622    if (@{$$chip{detected}}) {
4623      if (@{$$chip{misdetected}}) {
4624        print "(should be inserted but causes problems):\n";
4625      } else {
4626        print "(should be inserted):\n";
4627      }
4628    } else {
4629      if (@{$$chip{misdetected}}) {
4630        print "(may not be inserted):\n";
4631      } else {
4632        print "(should not be inserted, but is harmless):\n";
4633      }
4634    }
4635    if (@{$$chip{detected}}) {
4636      print "  Detects correctly:\n";
4637      print_chips_report $chip->{detected};
4638    }
4639    if (@{$$chip{misdetected}}) {
4640      print "  Misdetects:\n";
4641      print_chips_report $chip->{misdetected};
4642    }
4643  }
4644
4645  print "\n\n",
4646        " I will now generate the commands needed to load the I2C modules.\n",
4647        " Sometimes, a chip is available both through the ISA bus and an ",
4648        "I2C bus.\n",
4649        " ISA bus access is faster, but you need to load an additional driver ",
4650        "module\n",
4651        " for it. If you have the choice, do you want to use the ISA bus or ",
4652        "the\n",
4653        " I2C/SMBus (ISA/smbus)? ";
4654  my $use_isa = not <STDIN> =~ /\s*[Ss]/;
4655     
4656  my ($modprobes,$configfile) = generate_modprobes $use_isa;
4657  print "\nTo make the sensors modules behave correctly, add these lines to\n",
4658        "$modules_conf:\n\n";
4659  print "#----cut here----\n";
4660  print $configfile;
4661  print "#----cut here----\n";
4662  print "\nTo load everything that is needed, add this to some /etc/rc* ",
4663        "file:\n\n";
4664  print "#----cut here----\n";
4665  print $modprobes;
4666  print "# sleep 2 # optional\n",
4667        "/usr/local/bin/sensors -s # recommended\n";
4668  print "#----cut here----\n";
4669  print "\nWARNING! If you have some things built into your kernel, the list above\n",
4670        "will contain too many modules. Skip the appropriate ones! You really should\n",
4671        "try these commands right now to make sure everything is working properly.\n",
4672        "Monitoring programs won't work until it's done.\n";
4673 
4674  my $have_sysconfig = -d '/etc/sysconfig';
4675  print "\nDo you want to generate /etc/sysconfig/lm_sensors? (".
4676    ($have_sysconfig?"YES/no":"yes/NO")."): ";
4677  if ($> != 0) {
4678    print "\nAs you are not root, we shall skip this step.\n";
4679  } else {
4680    $_ = <STDIN>;
4681    if (($have_sysconfig and not m/^\s*[Nn]/) or m/^\s*[Yy]/) {
4682      unless ($have_sysconfig) {
4683        mkdir '/etc/sysconfig', 0777
4684          or die "Sorry, can't create /etc/sysconfig ($!)?!?";
4685      }
4686      open(SYSCONFIG, ">/etc/sysconfig/lm_sensors")
4687        or die "Sorry, can't create /etc/sysconfig/lm_sensors ($!)?!?";
4688      print SYSCONFIG <<'EOT';
4689#    /etc/sysconfig/sensors - Defines modules loaded by /etc/rc.d/init.d/lm_sensors
4690#    Copyright (c) 1998 - 2001  Frodo Looijaard <frodol@dds.nl>
4691#
4692#    This program is free software; you can redistribute it and/or modify
4693#    it under the terms of the GNU General Public License as published by
4694#    the Free Software Foundation; either version 2 of the License, or
4695#    (at your option) any later version.
4696#
4697#    This program is distributed in the hope that it will be useful,
4698#    but WITHOUT ANY WARRANTY; without even the implied warranty of
4699#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4700#    GNU General Public License for more details.
4701#
4702#    You should have received a copy of the GNU General Public License
4703#    along with this program; if not, write to the Free Software
4704#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
4705#
4706#
4707# See also the lm_sensors homepage at:
4708#     http://www2.lm-sensors.nu/~lm78/index.html
4709#
4710# This file is used by /etc/rc.d/init.d/lm_sensors and defines the modules to
4711# be loaded/unloaded. This file is sourced into /etc/rc.d/init.d/lm_sensors.
4712#
4713# The format of this file is a shell script that simply defines the modules
4714# in order as normal variables with the special names:
4715#    MODULE_0, MODULE_1, MODULE_2, etc.
4716#
4717# List the modules that are to be loaded for your system
4718#
4719EOT
4720      print SYSCONFIG
4721       "# Generated by sensors-detect on " . scalar localtime() . "\n";
4722      my @modules = grep /^modprobe /, split "\n", $modprobes;
4723      my $i = 0;
4724      my $sysconfig = "";
4725      foreach (@modules) {
4726        s/^modprobe //;
4727        $sysconfig .= "MODULE_$i=$_\n";
4728        $i++;
4729      }
4730      print SYSCONFIG $sysconfig;
4731      close(SYSCONFIG);
4732      print "Copy prog/init/lm_sensors.init to /etc/rc.d/init.d/lm_sensors\n";
4733      print "for initialization at boot time.\n";
4734    }
4735  }
4736}
4737
4738main;
Note: See TracBrowser for help on using the browser.